Skip to content

Render the design system as the values it is made of [#29] - #168

Merged
iderex merged 4 commits into
mainfrom
the-design-system-page
Aug 16, 2026
Merged

Render the design system as the values it is made of [#29]#168
iderex merged 4 commits into
mainfrom
the-design-system-page

Conversation

@iderex

@iderex iderex commented Aug 16, 2026

Copy link
Copy Markdown
Contributor

Closes #29.

What was wrong

The design system was served from another repository as a specification, and this
build produced no page for it. The part that was missing was not the markup. The
file the values come from holds two different kinds of thing under one shape:
values a client has to meet, and sentences the file writes about itself so that
whoever opens it knows what they are looking at. A page rendering both does not
fit the document line the speed budget fixes, and a page deciding by key name
gets that file wrong, because it carries a weight that is a sentence and a
weight that is the number 540.

What this does

The page lists every leaf of the pinned copy that carries a value, decided by the
value and never by the key, and it prints the counts of what it listed and what
it did not so the split can be read off the page rather than out of the
generator. Where a value can be drawn it is drawn with that same value: a colour
is its own background and its own foreground at once, a radius is the corner it
makes, a type role is drawn at the size it is given, and each colour vision
preset's accent is drawn as the ring it makes in both schemes. Nothing on the
page states a size, a colour or a weight this repository chose.

Every value a drawing uses is read twice. This package reads it against one of
two anchored shapes first, a number that can stand in front of a unit or a
hexadecimal colour, and a value of any other shape is not drawn and is printed
with the path it sits at. Then the frame writes the property and hands the engine
the value, so it is read in a value position and filtered there as well. Nothing
converts a string into markup the engine writes out unread.

A group that can no longer be drawn reds the build and names itself. The file is
published elsewhere, so a renamed key is how that arrives, and a page that
silently stopped demonstrating what it says it demonstrates is worse than a red
build.

Both budgets are on the page under headings saying whose each one is. The client
numbers come from the same file the values do and the site numbers from the
constants the row that refuses a page reads, so neither table can go on stating a
limit nothing holds anybody to.

The rule, the two answers that were available and were not taken, and what each
of them would have cost are in
decisions/0014-what-the-design-system-page-renders.md.

The means is Go and the template package already in the toolchain. The page is
one more writer beside the four this build already has, it needs no dependency,
and the suites that exist judge it.

One thing the page does not draw

A type role is drawn at its size and states its weight in words. The property
that would draw a weight may not appear in what the build reads at all, which is
the row keeping a weight from being defined anywhere but the token file, and this
page is inside that row's subject like every other build input. So the
alternative was a page that weakens that row rather than a page that draws one
more thing, and the weight is stated beside the sample instead.

What the gate says

Run at a948fa4, the head this branch pushes.

go run . ci
gate: 7 legs, in order: format, vet, test, build, links, sitemap, invariants
  needs-network was not asked for. Asking costs a request to the public name from whatever machine runs it, and a verdict that moves when somebody else's service does rather than when this tree changes. Ask with: go run ./harness/needs-network
  format: ok, 52 file(s)
  vet: ok
  test: ok, 25 test file(s)
  build: ok, 8 file(s)
  links: every reference that stays inside this site resolves to a file the build wrote
  sitemap: every page the build wrote is listed once, and every entry has a page behind it
  invariants: ok, 36 rule(s) decided, 1 owed and not decided
7 of 7 legs ran. None was skipped.

go run . build | grep design-system
wrote dist/design-system.html (19173 bytes, 154 value(s) listed, 36 drawn, 52 sentence(s) not listed)

go run . reproduce | tail -2
reproduce: two builds of ., compared byte for byte
  8 file(s), identical in both builds

The guards, each shown going red for the reason it names

Five one-change near misses, each the mistake somebody actually makes, with the
tree restored between them.

The rule reading only the end of the value, which drops the half that catches a
leaf whose prose does not end where the leaf does:

go test ./internal/site -run 'Sentence|StatesHowMuch' -count=1
--- FAIL: TestASentenceThatDoesNotEndTheLeafIsStillProse (0.04s)
    designsystem_test.go:244: the page lists a leaf carrying prose, so the rule read only the end of the value
    designsystem_test.go:247: the page did not count the leaf carrying prose as one

A leaf holding nothing read as a value spelled null:

go test ./internal/site -run 'LeafHoldingNothing' -count=1
--- FAIL: TestALeafHoldingNothingIsCountedAsCarryingNoValue (0.04s)
    designsystem_test.go:227: the page does not count the leaf holding nothing, so it was read as a value or dropped in silence
    designsystem_test.go:230: the page lists the leaf holding nothing as though it were a value

The swatch handed a colour that is not the value beside it, which is the failure
that renders perfectly:

go test ./internal/site -run 'ColourIsDrawn' -count=1
--- FAIL: TestAColourIsDrawnWithTheColourItStates (0.04s)
    designsystem_test.go:305: the page does not draw the accent with itself, and a swatch built from a second copy is the failure this page exists against

A group that emptied rendering as a heading with nothing under it:

go test ./internal/site -run 'GroupThatCanNoLonger' -count=1
    --- FAIL: TestAGroupThatCanNoLongerBeDrawnRedsTheBuild/the_ring_width (0.04s)
        designsystem_test.go:347: the build accepted a token file the page cannot be drawn from
    --- FAIL: TestAGroupThatCanNoLongerBeDrawnRedsTheBuild/the_radius (0.01s)
        designsystem_test.go:347: the build accepted a token file the page cannot be drawn from
    --- FAIL: TestAGroupThatCanNoLongerBeDrawnRedsTheBuild/the_role_size (0.02s)
        designsystem_test.go:347: the build accepted a token file the page cannot be drawn from

A value of the wrong shape drawn anyway. The change disables the reading of a
number and leaves the reading of a colour in place, so two of the three cases go
red and the third is the one the other reading holds. That is the change being
one change rather than the case being weaker:

go test ./internal/site -run 'ShapeADrawing' -count=1
    --- FAIL: TestAValueThatIsNotTheShapeADrawingNeedsIsRefused/a_ring_width_carrying_more_than_a_number (0.01s)
        designsystem_test.go:376: the build accepted a token file the page cannot be drawn from
    --- FAIL: TestAValueThatIsNotTheShapeADrawingNeedsIsRefused/a_radius_carrying_a_unit_of_its_own (0.02s)
        designsystem_test.go:376: the build accepted a token file the page cannot be drawn from

Every fixture in that suite is a token file the suite wrote. A case asserting the
real copy's 154 values would be a statement about the copy on the day it ran, and
it would go red the next time somebody publishes a colour, which is the one event
this page has to survive without anybody editing it. The case that says so
directly adds a value and a sentence to a fixture copy and asks what the page
did.

A correction to a measurement this page was planned against

The reading that put the leanest rendering of the values at 7861 bytes measured
rows with no end tags. This repository reads every produced page strictly and
refuses an element that is not closed, so those rows are not available here and
the real list is larger. The list this page writes is 10890 bytes over the same
154 values, and the page fits anyway.

What is left over, and it is small

python -c "s=open('dist/design-system.html',encoding='utf-8').read();a=s.index('<dl>');b=s.index('</dl>')+5;d=s[a:b];print(20480-len(s), round(len(d)/d.count('<dt>'),1))"
1307 70.7

Run at a948fa4. So 1307 bytes are left under the document line and a value costs
about 71 of them, which is room for eighteen more values before the row that
refuses a page over the line refuses this one, by name. The record above states
that as the condition for reconsidering it, and the two answers it did not take
are what a refusal there would be a request to reconsider.

What this does not do

It does not reopen the address scheme and it does not move the document line.
Both were available answers to the same question and each moves a record that was
taken elsewhere, so neither is taken here.

It does not reproduce the motion the served page has. Those durations are not
values in the token file, so a page carrying them would be typing them into this
tree, and whether they become tokens is a question about that file rather than
about this page.

Reading

This change carries no second reader. The evidence above stands in place of one:
the gate at the pushed head, the build reporting what the page is made of, two
builds compared byte for byte, and each of the five guards shown going red on its
own one-change near miss.

The design system was a specification served from another repository and this
build produced no page for it. What was missing was not the markup but the rule
underneath it: the file the values come from holds values and holds the file's
own sentences about itself under one shape, so a page rendering everything does
not fit the document line the budget fixes, and a page rendering by key name
gets the two weights in that file wrong whichever side it picks.

The page lists every leaf that carries a value, decided by the value and never
by the key, and prints the counts of what it listed and what it did not so the
split can be audited off the page. Where a value can be drawn it is drawn with
that same value: a colour is its own background and foreground, a radius is the
corner it makes, a type role is drawn at its own size and weight, and each
colour vision preset's accent is the ring it makes in both schemes. A swatch
built from a second copy of a colour renders perfectly while disagreeing with
the number beside it, which is the failure this shape removes.

A group that can no longer be drawn reds the build and names itself, because the
file is published elsewhere and a renamed key would otherwise arrive as a page
that quietly stopped demonstrating what it says it demonstrates.

The page states both budgets and says whose each one is. The client numbers come
from the same file the values do and the site numbers from the constants the row
that refuses a page reads, so neither table can state a limit nothing holds
anybody to.

Signed-off-by: Nils Lehnen <30603423+iderex@users.noreply.github.com>
@iderex iderex added the enhancement New feature or request label Aug 16, 2026
@iderex iderex self-assigned this Aug 16, 2026
@iderex iderex added this to the The pages milestone Aug 16, 2026
Comment thread internal/site/designsystem.go Fixed
Comment thread internal/site/designsystem.go Fixed
Comment thread internal/site/designsystem.go Fixed
Comment thread internal/site/designsystem.go Fixed
The static analysis over the generator refused the four conversions that put a
declaration into a style attribute, and it was right to. A declaration is the one
place on this page where a value is markup rather than text, and the file the
values come from is published elsewhere, so a value carrying a semicolon would
have arrived on the page as a second declaration nobody wrote.

Every value a drawing is built out of now goes through one of two readings first,
and both are anchored at each end: a number that can stand in front of a unit, or
a hexadecimal colour. A value of any other shape is not drawn and the build
prints it with the path it sits at, because a group that is one sample short
looks exactly like a group that is complete.

Found by the semgrep leg on the first push of this branch.

Signed-off-by: Nils Lehnen <30603423+iderex@users.noreply.github.com>
Comment thread internal/site/designsystem.go Fixed
Comment thread internal/site/designsystem.go Fixed
Comment thread internal/site/designsystem.go Fixed
iderex added 2 commits August 17, 2026 00:40
The four reasons written beside the conversions did not hold the finding off,
because the directive sat at the top of a comment block and the analyser reads
only the line immediately above the code. So the run stayed red for a reason
that had nothing to do with what the reasons said.

The reason now sits above the directive and the directive sits on the line
before the conversion. Nothing about what is converted changed, and the readings
that make each conversion safe are the ones the last change added.

Found by the semgrep leg reporting the same four findings after the reasons were
written.

Signed-off-by: Nils Lehnen <30603423+iderex@users.noreply.github.com>
The four conversions the last change explained were still reported by the code
scanning upload, because the analyser's document carries a suppressed finding and
the tab keeps it open. Working around that would have meant dismissing four
alerts on a public repository for a construct that did not have to be there.

The frame writes the property and hands the engine the value, so every value is
now read in a value position and filtered by the template engine as well as by
the two readings this page already ran it through. Nothing converts a string into
markup any more, so there is no finding to explain.

One thing is lost and it is worth naming rather than leaving to be found. A type
role is drawn at its size and states its weight in words, because the property
that would draw a weight may not appear in what the build reads at all. That is
the row keeping a weight from being defined anywhere but the token file, and this
page is inside its subject like every other build input, so the alternative was a
page that weakens that row.

Signed-off-by: Nils Lehnen <30603423+iderex@users.noreply.github.com>
@iderex
iderex merged commit 3f8cf5d into main Aug 16, 2026
17 checks passed
@iderex
iderex deleted the the-design-system-page branch August 16, 2026 22:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

The design system as a page

2 participants