# Cosmos changelog

Every published Cosmos release, newest first. The current release's changes are the first section below.

## 2.3.0 · current

- Adds C27 and the light tokens: eight gradients and two shadows composed only from the existing anchors.
- C11 now specifies one deterministic edge star layer with a published parity fixture, and moves to the new atmosphere section.
- The focus aperture is drawn as a quasar: core, corona and optional accretion ring (C03, A03, M01).
- The primary action fills with the action gradient (C12, P04). Watch interactive mode may show one static corona on its marker (W01).
- Sky and orrery fields own no decorative stars (M04). No anchor color, rule ID or section URL changed.
- The theme adapters become the only definition of a surface: every interactive profile publishes the same set of semantic roles and a display profile publishes fewer, and a component reads roles rather than anchors.
- Three roles are new. `accentText` carries an accent that is used as text, `faint` is the third text step and `line` is a translucent hairline no hex can express.
- Gradients and shadows are now per-profile. A profile that does not run one resolves the token to `none` and the element falls back to its flat role color.
- C06 gains the selection rule: follow the system preference until the visitor chooses, and an explicit choice persists.
- C27 names the one ambient motion: the focal object's accretion disc revolves about the core every 40-90 s, and the accretion ring no longer rotates.
- The ring stopped moving because C27 already said light never carries the only boundary, and a rotating outline is a boundary. What moves now is geometry the visitor was reading as depth.
- No anchor color, rule ID or section URL changed.
- Six published claims are now enforced rather than stated. The conformance figures are compared between the token block and the three rules that name them, so a target cannot drift from the number a port is measured against; the parity fixture publishes its iteration count, sample count, duration table and per-motif timing, and each is checked against a second source or against a floor a port can rely on; the manifest names every document the product declares, including the two it published but never listed; the rule-ID shape both schemas declare is asserted instead of inferred from the prefix; the physical-placement ban reaches the landing stylesheet, with one named exemption for the marker the script positions in the SVG coordinate system; and the browser tier runs from one command that builds, serves what it built and stops the server, so playback, focus and no-JS rendering no longer depend on someone remembering a second command.
- Six facts that had more than one owner now have one, and the gate says which file owns each. The theme profile list is read from the token file by the generator and off the rendered picker by the browser instead of being written out three times, so a fifth profile is one edit; the origin, the logo and the stylesheet are read from the registry rather than restated in the generator, which also drops a field no module read; the anchor map, the sRGB channel decode, the six-decimal fixture rounding and the camel-to-kebab rule each have a single owner, and a second copy is now a gate failure rather than a number that quietly disagrees with its twin; every published byte budget is checked against an assertion, so a ceiling listed in three tables and measured in none cannot pass; and the rule-prefix vocabulary is owned once, so the part documents, the component slices and the rule links are derived from it together. Nothing published changes.
- The eight per-part payloads are listed as resources instead of being published unannounced. Each part publishes a tokens document and a rules document, and an agent reading the catalog was told about neither: llms.txt and the ARD catalog enumerate what the product declares, and these were in neither list, so a document that exists was indistinguishable from one that does not. They are now declared, and the generator takes its published resource map from that same declaration rather than restating fourteen names, so a payload cannot be added without being announced. Two more owners went with it: humans.txt describes the accessibility target from the product that claims it rather than naming Cosmos, and the 404 page carries its own styling, because the one page that must render when a path is wrong cannot depend on a product stylesheet resolving. The published Markdown is now rendered once per part and shared, which changed no byte, and the two schemas state their own counts instead of typing numbers that were already wrong.
- The anchor reservation is published once. --anchor-reserved was read by two rules and assigned nowhere, so each of them carried its own 144px fallback: every in-page anchor jump on a part page landed about 31px lower than intended against a header that measures 113px, and the number a maintainer read in a comment was a third figure that matched neither. The header now publishes the measurement at :root, the two rules read it with no fallback, and the gate requires it to be declared exactly once and to be a length -- a variable nobody assigns, declared twice, or given a second fallback all fail instead of shipping.
- A stored motion preference is now honoured from the first frame. The tier used to be restored by a deferred module, so a reader who asked for still frames watched the ambient disc revolve for the whole of the load; the inline script in the document head restores it alongside the theme, generated from the same tier list the picker renders, so a tier added to the picker is restored by the same edit. The tier list has one owner and the client reads it off the rendered radios rather than carrying its own copy. The browser chrome is painted from the profile that was chosen: selecting Astronomy or Watch Ambient previously left a light-mode browser showing the cream theme colour above a page painted near-black, because only Daylight was ever given its own colour. Every picker option now publishes that profile colour, and the page chrome colour is read from the token file rather than typed, so a profile whose background is not a paintable hex fails the build instead of shipping.
- The build does the work once. The gate generated every published document a second time in order to compare it with the disk, and the four words of language naming in humans.txt paid for a cold Intl.DisplayNames on each of those passes; both now happen once per process. The per-pin document reads, the CSS variable lookup behind 223 variable references on one page, the family lookup behind every gallery card and the seventeen painters behind each state drawing are resolved once and reused. No published byte changed, and none of this was a measurable cost at the current size -- it is recorded so it is not mistaken for a defect later.
- The generation path is checked where it happens. The static asset tree was copied by the build and verified by nothing, while the log line reported the two compiled files as though they were the whole job; the check now walks the copied tree and fails on a missing or drifted file, and the count it prints is the number of files that actually matter. One escaping owner prints every label: it escapes a quote as well as the three XML-significant characters, and the sitemap escapes through it as XML rather than as HTML, so an apostrophe in a product name is a correct document instead of a broken one. The root redirect is derived from the landing locale rather than typed, so it stops being right by coincidence. The note sizes that appear in release notes name the document they cannot find instead of publishing Infinity or throwing a bare type error, and a part that publishes no payload is a build failure rather than an empty range. One sentence no longer counts the pages it describes; a derived count read worse than no count.
- The gate now inverts the oklch notation this document publishes, not only the component triple behind it. C29 promises every published web oklch resolves back to the sRGB value it came from, and the check that made that promise was reading a DTCG artefact that no reader ever sees while the formatted string in the token registry table went unchecked -- a rounding regression in the notation itself would have shipped. Each published notation is now parsed, resolved and compared with the hex beside it in the same row. The dead code that hid this is gone too: the parse existed for exactly this check and nothing called it. A star colour that nothing publishes is now a build failure rather than a sky that quietly drops its stars, and the accent index in the starfield algorithm is derived from the accent list instead of a literal 3 that only matched the four accents it was written beside.
- The generated tables now speak one language. C09 listed its corner radii as bare numbers while M06, two rules away, named every role, so a reader of C09 could not tell which value was the control and which was the sheet without opening tokens.json; both now read the same mapping the table beside them prints. The motion section published two tables a few lines apart in different vocabularies for the same easing purpose, and the motif table abbreviated them through an identity map that added nothing; both now name the purpose as the mapping does. The OLED watch specimen painted its plate from a hand-typed #000 -- the one colour in the stylesheet that no token owned -- and the token pin beside it had to be widened past that literal to stop three strings freezing with it, so on a light page the reading stayed on dark-profile values above a plate every other specimen had recoloured. The plate is its own element now, painted from a published profile value, and its type follows the theme: Compass, 042 and the last reading each move with the profile. No stylesheet rule may paint with a literal hex again, which is what makes the next one a failure rather than a surprise.
- Every URL in this release moved. The design system is published at /cosmos/design rather than at a top-level path of its own, because /cosmos is where this origin keeps its reference work and the design system is the first sub-context in it rather than the only thing that will ever live there. Nothing about a rule, a token or a component changed; every canonical URL, sitemap entry, agent resource, redirect and header moved with it, and the old address returns the overview rather than a 404 so a link already in the wild still arrives somewhere. The structure is declared once -- the context in the space descriptor, the sub-context beside it, and a product base derived from both -- so publishing the next reference system under /cosmos is a descriptor rather than another root typed in a dozen places.
- Adds C30: easing is published per platform part in tokens.json under platformAdapters, so a part reads its own curves instead of inferring them.
- C09 and M06 state the Android shape scale (8 / 10 / 14 / 20 / 28 dp) in place of the three-step 12 / 20 / 28, because a handheld screen steps from a 48 dp target to a full-bleed overlay in five increments where a pointer surface needs three, and the Wear round and capsule shapes become normative rather than implied. Both keep their ID and their acceptance criterion.
- The platform mapping is authored in tokens.json as the normative source for every part. A product that diverges from it is out of date with the mapping, and the mapping is never revised to match a product.
- Spacing is unchanged: 1 unit is 1 CSS px on web and 1 dp natively, and no platform publishes its own scale.
- C28 is merged into C09. It repeated the same mapping from a second rule, and one rule that owns the geometry cannot leave a copy of it behind when the mapping changes. No rule ID changed meaning; C28 is free for the next common rule.
- C09, M06 and C17 no longer type a number. The spacing scale, the radius scale and the three durations are read from the token file, so the prose cannot drift from the mapping that an agent reads.
- Every platform part now runs the same three durations. The Android and Wear mapping publishes 150ms feedback, 300ms local state and 500ms context change, and C17 reads that table rather than naming one figure per platform.
- W01 states that corona is the only gradient a watch screen may use, which is what the atmosphere table already implied and what a part payload needs in order to ship one gradient instead of eight.
- Each of the four parts now publishes tokens.json and rules.json at /cosmos/design/<part>/ carrying the common foundations plus that part's own adapter, so an agent building one platform no longer reads the other three.
- C22 owns those addresses: a payload carries exactly one adapter, publishes the scope it was filtered to, and stays inside a published byte budget. Everything it shares is byte-identical to the canonical document, and filtering may drop a profile but never rewrite one.
- The composited contrast measurements move out of tokens.json into contrast-pairs.json, with the reason to fetch it stated in every file that points at it.
- C05 now names that document as the place the measurements live; C22 owns the rule that a sometimes-needed document gets its own address.
- The token document is 77.2 KiB with the measurements out of it, and one part payload is 80.9 KiB–112.3 KiB against 166.8 KiB for the canonical union. Every measured ratio is unchanged.
- A part payload is now filtered to what that part runs, and the scope it was filtered to is published in the document: the profiles it selects, the gradients its surfaces use, and whether it draws the star layer. The wrist payload, the narrowest of the four, is 25.8 KiB of tokens: a round screen draws one glow and no stars, beside the action and rim fills every part inherits.
- The glows a part draws follow the atmosphere table, which is a table of profiles and so cannot say which of them a round screen has room for; the published scope is the owner and the table covers its ambient half. Deep Space draws the whole grammar, Daylight keeps horizon and spectrum, astronomy red and watch ambient draw none, and a watch screen narrows further to one. A floor sits under all four: the action gradient of C12 and the rim of C10 are inherited by every part, so no payload drops them, and no rule can be satisfied from a document that filtered its own token out.
- The oklch projection is published once, as real colour tokens, instead of once per web part as a block of notation strings, and only the parts that can emit an oklch value carry it. It projects the profiles a part actually runs, not all four.
- The token files conform to the design-token standard: a dp radius is a number with its unit in the extension, a native shape is a shape rather than a fake token type, and no group mixes a bare value with its tokens. A tool that reads these files no longer skips a colour.
- Adds C29: colour is authored and verified in sRGB, and every published colour also carries the oklch projection the web parts may author in.
- The Deep Space token registry gains an oklch column. Every hex value is unchanged; the projection is derived, so the two notations cannot disagree.
- Android and Wear declare sRGB in the platform mapping, because neither toolkit has an Oklab colour space to author in.
- Adds C31: a state change is animated by naming the motif whose job is that change. Seven motifs cover the recurring changes — a target acquired, a list revealed, a horizon sweep, the spine advancing, a sheet rising, data going stale, a route change — each publishing its trigger, steps, allowed properties, duration, easing, tier behaviour and CSS, Compose and Wear mapping. A change with no motif does not animate.
- The motifs are published in motion.json, outside the token payloads, with a fetchWhen note saying when to read it. The token files carry the address and a payload never embeds the set, so an agent working on one state change does not read seven choreographies to animate a dim.
- The same document publishes a curve parity fixture: every published easing curve sampled at a fixed number of points by a fixed number of bisection steps, the way the star field publishes its own. A native port reproduces the numbers instead of trusting its toolkit to match, and the fixture carries both the web and the native departure curve because they genuinely differ.
- A section can now carry more than one table, so the motion section publishes the easing mapping and the motif set side by side. The easing purposes are read from the motif module rather than restated, so a table row and a motif cannot name different curves.
- Adds the component index: components.json names, per component, its rule IDs, theme roles, layer and corner role, states, motif and the counterpart each product already has, sliced by platform part. It carries references only — a treatment restated is a second answer that can disagree with the rule it summarises.
- The shared state matrix grows from eight rows to eleven and is now generated. Hover and pressed are separate because a pointer and a finger are different, and confirmed, stale and offline are named because a surface that reaches a data state has to show its confidence. Generated from one vocabulary, so a state with no written treatment fails verification instead of appearing in a table with nothing beside it.
- A component names the motif that animates it and inherits its duration and easing from that motif, so a component repeating the timing was a second copy of motion.json; three actions named a feedback duration beside a motif whose own is state. A component with no motif publishes no timing, which is how a stage that does not animate is stated.
- Every component is now shown at /cosmos/design/gallery, one route per family so each stays inside the per-route HTML budget and a reader can link to one family instead of all of them. A card is a rendering, not a second contract: the state matrix is the rule's own wording, the timing and choreography from the named motif, the colours from the published tokens.
- A gallery card is static HTML. The state matrix is a table, the motif is four still SVG frames, and the Play control ships disabled, so the page explains itself with scripting off and under every theme. Playback is a courtesy on top: one run at a time, nothing on its own, a run that leaves the screen ends rather than resuming unseen, and Static removes the control.
- The duration a card runs is published as a token role rather than a figure, so the client resolves it from the stylesheet and a card cannot state a duration the mapping has moved. Cross-page view transitions between the parts are CSS only and only where the reader has not asked for reduced motion.
- The manifest names the galleries, their families and the components each one shows, derived from the registry. The routes were reachable from the navigation and llms.txt but not from the document an agent loads first.
- Every page carries the site chrome once. A shared page shell let one caller emit its own navigation beside the shell's, putting a second sticky header on six routes; the shell owns the chrome and a check holds each page to one of each.
- A drawing is only as honest as the state it claims to show, and the illustration helpers emitted one style attribute per colour. A browser kept the first and dropped the rest, so 53 gallery and five specimen shapes lost their fill or stroke and a card could not show what it claimed. One helper emits a single merged attribute, and a check refuses a repeated one.
- Every component now accounts for all eleven states, naming the ones it has and the ones it has deliberately opted out of. Of 187 state slots, 102 were unaccounted for, so a component with one state passed. A component opting out gives one of nine codes, each published once as prose, because applicability cannot be derived: the components share sixteen distinct state sets.
- The shared state matrix gains a fourth column naming how many components opt out of each state and by which reason, so coverage is visible on the page.
- A purpose is not a curve: web publishes standard, emphasis, entrance and exit while native adds transform, so a motif naming transform resolved to nothing on a web part and the gate said nothing. Every motif must now resolve on every part it runs on.
- Budget failure messages name the budget and quote its live ceiling, instead of typing a figure that stopped being true when a budget was raised.
- The gallery pages carry the tier picker and the tier is remembered. A reader comparing tiers across seven pages had lost the choice on every navigation, and the picker lived only on the foundations page, so Reduced and Static were unreachable from a gallery. The gallery index carries no picker: it has nothing to play and arrives carrying the stored tier.
- Browser verification covers all thirteen routes and checks the gallery across all three tiers: nothing autoplays, a Static run cannot start even when its button is clicked directly, starting one demo settles the other, and a Reduced run moves no frame and settles into the state a default run does. The tiers are read from the published picker, so a check cannot invent one.
- A run is a crossfade in every tier that has one. It was not: the transition sat on the drawing rather than the frame the script marks, the reduced tier pinned every frame opaque, and both reduced-motion blankets reached the frame with no transition allowed. The fade is not scoped to a tier, because scoping it to Reduced left the reduced run the smoother of the two.
- A card fits a narrow column at large text: the breadcrumb could not wrap and an anatomy identifier has no space to break in, so a 320-pixel page scrolled sideways at doubled text.
- The mark that opens a section label is the brand signature, so it paints spectrum rather than horizon. Horizon is the token for a 1-2 px light line and corona and accretion belong to the single focal object, so a page of eyebrows was a page of light lines standing in for a mark. Spectrum is published in every profile that carries branding, and in the profile that carries none the mark is absent rather than borrowed.
- Focusing a control in the header no longer scrolls the page. The document reserves space above each scroll-into-view target so an anchor jump clears the header, and a header control is already inside that reservation, so focusing one scrolled the page up by 490 pixels on Chromium and 236 on WebKit, from the theme select and the brand link alike. A control cancels it with the reservation the document already publishes.
- A drawing is repaired at the source: a name resolves to the variable that publishes it, and a name nothing publishes fails the build. Every primary action, chip and focus ring had rendered as a black rectangle, because the semantic roles are published under the cosmos prefix and the layers under layer-, so a hand-written var(--action) named nothing and an SVG fill fell back to black. The colours that happened to be aliases painted correctly, which is what hid it.
- A card draws every state it declares and no two of its drawings are the same; it used to draw only the first, so a card listed up to nine treatments and showed one, and thirty-two of its sixty-eight drawings were the resting picture under another caption. Hover, pressed and disabled are the tone of a surface, and confirmation, offline, a pending mark, a danger glyph, a selection check and an age label are facts about the surface rather than the shape inside it, so those are drawn once for every component instead of seventeen times.
- The four stills of a motion card are one drawing at four points along the motif, and what differs between them is a share on the progress bar beside it. It used to switch the last frame to pending, inventing a state the motif never claimed to cross, and then to fade the drawing itself, which is what a spend on a motif means when every motif here spends opacity. Fifty-three drawings also carried a gradient and a rect nothing referenced, which is why a card could not afford its states.
- A still no longer fades. Every drawing in the gallery carries a label, and in Daylight that label is 4.64:1 on its own action fill, which is under the 4.5 C05 requires for normal text once it is dimmed by a fifth — so a frame has no dim available to it and the run fades the bar instead, which carries no words. A check composites the label and the caption in every profile and refuses an opacity on a frame, on the drawing inside it, or inline.
- Recorded deviation: the progress bar under a motion strip paints the horizon gradient at 3px. C27 gives horizon to one- and two-pixel light lines and says light never carries status, and a progress bar is status. It stays, because it reads as a deliberate choice and changing it silently would lose a visual nobody asked to lose.
- The release notes live in changelog.md alone, and the index points at them. They had become the larger half of the index, which is why its ceiling had to be raised twice and why a defect fix worth a fifth of a kilobyte was nearly deleted to fit under a limit the notes themselves had created. The index is a map of this document; the notes are the document's history.
- A scrim is painted as a scrim. The dialog drawing outlined its backdrop with the scrim token, which is a stacking tier rather than a colour, so the declaration was dropped and the shape was not on the page at all — the one component whose subject is a modal over a scrim was the one drawing with no scrim. It is now the void anchor at half strength, laid down before the modal. A painted token says which property it is read by, so a layer can no longer be painted as a colour, and a check holds every published page to that.
- The browser suite now watches every page it opens. It opened three — the width sweep, the parked-focus journey and the no-JS document — and attached its error and failed-response listeners to the first, so a throw in the two journeys most likely to fail passed silently while every assertion after them still held. Every catalog entry is now rewritten to the origin under test whatever that origin is, so a catalog that moves cannot be read from production and reported as a pass, and the URL the browser ends up on is compared with the path the registry declares.
- The landing pages are checked, which means the space holds budgets of its own. Four pages an origin publishes at its root — including the only right-to-left document on the site — were generated, linked, budgeted elsewhere and never looked at: every page check filtered on the specification's own path. They now carry the same one H1, unique id, live anchor, readable structured data and one attribute per element, are required to declare their direction from their locale, and are held to a ceiling the space declares. The specification's HTML, CSS and JavaScript budgets belonged to the specification, so adding the landing to them would have failed a gate that had only just started looking; the landing carries three of its own.
- A profile description states what its own profile carries. The note that a display profile has no interactive role sat in the template every profile was built from, so it was published thirteen times and three of those were about a profile the reader was not reading.
- The gallery stops asking for an accessibility it did not have. A selected chip filled with the identity accent and labelled it in ink, which measures 2.00:1, 2.96:1 and 1.00:1 across the three profiles that publish identity; selection is now a tonal treatment -- an accent ring and a check over the raised fill, with the label on the pair that reads. Gold focus is no longer borrowed to mark selection, so a selected state and a focused one are not the same ring. Heading order is a rule rather than a count, so a page cannot go from one h1 straight to h3; the four frames of a strip are named by position; a drawing is named by the component the registry publishes; the state matrix scrolls inside a focusable, named region like every other scroll container; the footer brand and the part download links carry the published target floor instead of a 29 px line box; and a motif the Static tier will not run is announced by a control that stays in the tab order, marked by aria-disabled rather than removed from it.
- Four sentences in this document contradicted another part of it. The surface budget said only the focal surface adds a rim border while the gradient grammar gives the rim to the focal or selected surface and the state matrix permits it, so the budget was amended to the answer the other two already gave. The same sentence required a surface called Canopy that no part of the registry publishes, so the one translucency allowance now names the role it uses and states the legibility floor without inventing a colour. The composited contrast document said eligibility was never stored per pair while every one of its 212 pairs stores it, so the sentence describes what it does. And two figures were typed into prose -- a role count and the version -- so both are now read from the record they belong to, and the checks that hold them are the reason a rule cannot name a surface the registry does not publish or a version the release record does not carry.
- C11 no longer types a number. Every star figure it states is read from the starfield module, which is the same source the agent brief reads, so the rule and the brief cannot disagree; and the Ink claim is restated as the cap the algorithm actually keeps -- at most a tenth of the layer in any one accent, so Ink is the majority -- because a 70% floor is not a property the generator can hold: measured, the accepted share is 69.6% on a 320px screen, where placement rejects one star of the layer it asked for. The clearance figure is gone with the token that carried it: the exclusion region is authored per surface in the same normalised coordinates the stars are placed in, and a published dimension nothing applied was a promise with no consumer.
- No anchor colour or section URL changed, so every section address stays valid.
