Skip to content

Print the token file's undecided contrast claims as owed [#211] - #215

Merged
iderex merged 1 commit into
mainfrom
tests/the-token-files-contrast-claims-are-printed-as-owed
Aug 29, 2026
Merged

Print the token file's undecided contrast claims as owed [#211]#215
iderex merged 1 commit into
mainfrom
tests/the-token-files-contrast-claims-are-printed-as-owed

Conversation

@iderex

@iderex iderex commented Aug 29, 2026

Copy link
Copy Markdown
Contributor

Closes nothing. #211 asks for a row that refuses a text token whose contrast
falls under the floor the token file declares, and that row cannot be built
here yet. This is the disclosure that says so on every run, and the reason is
below.

What was wrong

The role of the third ink step in data/design-tokens.json states two claims
about the file's own values:

python -c "import json;print(json.load(open('data/design-tokens.json'))['surface']['tokens']['ink-3']['role'])"
Tertiary text: labels, units, the year beside a title. It is a third step of the same scale and not a fainter one: it clears the same 4.5:1 floor as ink and ink-2 against every surface, and the distance from ink-2 is under one and a quarter of contrast ratio in the widest case. Reach for it where the words are ones a reader passes over, never to make text recede, because it will not.

Nothing in this tree decides either of them, and the gate said nothing about
that. At 80942fa:

go run . ci | tail -3
  sitemap: every page the build wrote is listed once, and every entry has a page behind it
  invariants: ok, 39 rule(s) decided, 1 owed and not decided
7 of 7 legs ran. None was skipped.

One owed entry, and it is the image-dimension one. A reader takes that line for
the whole of what this gate is meant to carry, and it was not.

Both margins are two hundredths wide, computed from the declared sRGB values
with the script on #36, saved as contrast.py and cut to the text scale. Run
2026-08-29 at aab9434:

python contrast.py
ink scale against every surface, floor 4.5 declared in the token file
  dark  ink    min 12.73  15.85 14.38 12.73
  dark  ink-2  min 5.52  6.87 6.23 5.52
  dark  ink-3  min 4.53  5.64 5.11 4.53
  light ink    min 16.93  18.47 19.27 16.93
  light ink-2  min 5.23  5.70 5.95 5.23
  light ink-3  min 4.52  4.92 5.14 4.52
widest ink-2 to ink-3 distance, under 1.25 declared in the token file
  1.23

So six hex values decide both, a one-step edit to any of them makes the file
assert something false, and every leg here stays green while the page that
renders the file goes on printing the sentence.

What this change does

One entry in the owed register, which is this repository's own form for a rule
the gate is meant to carry and cannot decide yet, and the second half of the
suite case that walks it.

go run . ci | tail -2
  invariants: ok, 39 rule(s) decided, 2 owed and not decided
7 of 7 legs ran. None was skipped.

go run . invariants | grep text-token-clears
  text-token-clears-the-declared-contrast-floor: not decided, waiting on data/design-tokens.json declaring the contrast floor and the step distance as fields rather than inside a sentence, which is #211. [...]

Both run at aab9434, the second elided for length.

Why the row itself is not in this change

#211 asks first that the file declare the floor and the step distance as fields,
because a number inside an English sentence cannot be read out of prose without
guessing and a floor typed into Go beside it is a second copy of one value.

That file is a pinned copy rather than something this repository authors:

sed -n '27,30p' decisions/0007-where-the-design-tokens-live.md
The machine-readable token file lives with the machine-readable data, in the
repository that holds the roster. This repository consumes it the way it
consumes the roster: a pinned copy in the tree, rendered by the build,
compared on a schedule against the published one. Nothing here defines a
token value.

and the copy agrees with the published file today, so two fields added here
would be read as a copy that has drifted rather than as a declaration:

go run . tokens
design tokens: 206 value(s) pinned in data/design-tokens.json
206 value(s) pinned, 206 published, 0 differing.

Both run 2026-08-29, the first at aab9434 and the second at 80942fa. So the
fields are declared where the values
are authored, and the row starts deciding on the re-pin that brings them here.
The reading behind that is written on #211.

That the guards bite

The entry is named by the suite, so a run that stopped printing what it is owed
reds. The three lines of Run that print the register, deleted:

go test ./internal/invariant/ -run TestRunNamesWhatItCouldNotDecide -count=1
--- FAIL: TestRunNamesWhatItCouldNotDecide (1.67s)
    invariant_test.go:1387: the run does not name image-dimensions-match-the-file as owed; it said:
    invariant_test.go:1387: the run does not name text-token-clears-the-declared-contrast-floor as owed; it said:

The citation case read owed[0]. It covered the whole register while that held
one entry and would have covered half of it from today. With the second entry
renamed to a row the table does decide, which is the mistake the case exists to
catch, the widened form refuses it and the old form passes the same tree:

go test ./internal/invariant/ -run TestTheCitationRowRefusesAnOwedRow -count=1
--- FAIL: TestTheCitationRowRefusesAnOwedRow (0.00s)
    invariant_test.go:810: the row passed a page citing page-carries-a-title, which this gate does not decide
FAIL

go test ./internal/invariant/ -run TestTheCitationRowRefusesAnOwedRow -count=1
ok  	github.com/Flowfin/site/internal/invariant	0.641s

The second run is the same tree with the case reverted to owed[0] and nothing
else changed. Both near-misses were reverted; the gate output above is the tree
being pushed.

The means

Go, in internal/invariant, because the register being extended is there and an
entry in it is a struct literal. Nothing is added to the toolchain and no
parallel apparatus appears. The row the entry stands in for is also Go for the
reason #211 gives, and this change does not build it.

Second reader

There is none. The ruleset on this branch requires no approving review, so nothing here
is held back for a second person:

gh api repos/Flowfin/site/rulesets/20572614 --jq '[.rules[].type]'
["deletion","non_fast_forward","pull_request","required_signatures"]

Run 2026-08-29. So no approval is asked for and none was given, and the merge
below is made by the same account that opened this. What stands in place of a
reader is the gate output and the two near-misses above.

The role of the third ink step in data/design-tokens.json states a contrast
floor of 4.5 against every surface and a bound of one and a quarter on its
distance from the second step. Nothing in this tree decides either, and the
gate said nothing about that: it printed 39 rules decided and one owed, which
reads as the whole of what this gate is meant to carry.

Six hex values decide both margins and both clear by two hundredths, so a
one-step edit to any of them makes the file assert something false and every
leg here stays green. The gap is now printed on every run with what would end
it, which is what the owed register is for.

What the row waits on is not this repository's to land. The file is a pinned
copy of one published elsewhere, so the fields the row would read are declared
where the values are authored and arrive here with the next re-pin.

The citation case beside it read only the first owed entry. It covered the
whole register while that held one entry and would have covered half of it
from today, without anybody editing the case, so it walks every entry now.

Signed-off-by: Nils Lehnen <30603423+iderex@users.noreply.github.com>
@iderex
iderex merged commit 951bcb1 into main Aug 29, 2026
17 checks passed
@iderex
iderex deleted the tests/the-token-files-contrast-claims-are-printed-as-owed branch August 29, 2026 11:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant