Skip to content

format: hold the text and picture families to the declaration they share - #94

Merged
donislawdev merged 2 commits into
mainfrom
format/narrowing-for-textenc
Sep 9, 2026
Merged

format: hold the text and picture families to the declaration they share#94
donislawdev merged 2 commits into
mainfrom
format/narrowing-for-textenc

Conversation

@donislawdev

Copy link
Copy Markdown
Owner

textenc.Properties() becomes textenc.Axes(names...) alongside textenc.Names(), the shape the archive package has had since the containers were unified. All three text formats take both axes and call it with both, so the narrowing has no dead call. It is there because the fourth format is already named and cannot take both: an HTML document has to be UTF-8 by its own specification, so the only encoding axis it could carry is the mark.

The gap was measured, not suspected

Two drifts were introduced on the tree, run, and reverted.

what was broken guards that stayed green what a user saw
md declares encoding itself - same kind, unit and default, one encoding fewer 11 md goes on writing utf-16be and stops offering it, so txt and xml answer one question and md answers another
bmp declares width itself, Min: 0 10 tfg formats bmp prints from 0 to 20000 while --set width=0 is refused with between 1 and 20000

The control matters: moving the default turned TestADeclaredDefaultIsTheOneTheFormatUses red at once. That half was already closed, which is why the mutation in the suite keeps the default in agreement - otherwise it would be proving another guard.

The second drift was caught only by the backstop in imagedim.Value, the one picturesides_test.go says a person cannot reach. A person reaches it exactly when a declaration drifts, and that was the case with no guard.

Why the picture guard is not a straight comparison

Largest, Default and Detail belong to the format and are supposed to differ - five ceilings, one default, and four sentences of which three would be made wrong by a shared one. So the guard rebuilds the declaration from the parts a format supplies and requires the result to be what is registered. That covers a field nobody has thought of yet, which a list of field comparisons would not.

Narrowing by name, not by value

No text format wants a narrower set of encodings, and all ten picture formats call Width and Height in pairs. Narrowing a value is what imagedim.Side already does, and it was built after ten different ceilings had been measured rather than before.

Evidence

  • tfg formats --json hashes to 0b1361a7294ab5b71b6acd39f13c9c74effa0a6df215f241fc3989636836dfc7 before and after
  • full suite green, ok internal/guard 275.8s
  • journey.py 300 of 300
  • both new mutations caught, staleness.py 919 patterns each occurring once
  • gofmt (from GOROOT) and go vet clean

Known limit, written down rather than fixed quietly

Both guards skip a name listed in deliberateHomonyms, and they skip it for every format rather than only for the one it excuses. Writing encoding there would silence half of the first guard. archiveaxes_test.go has no such door because it keeps no list. Narrowing the skip means changing the shape of another guard's list, so it is recorded in the guard's own comment and in the document.

🤖 Generated with Claude Code

donislawdev and others added 2 commits September 8, 2026 22:57
xlsx columns stopped at 64, with the reason "the width a person would
actually look at". That describes a document somebody reads, and this tool
writes fixtures somebody tests with - a ceiling belongs to the reader under
test. At 64 there was no way to build a sheet that asks Excel about its own
limit at all, while csv answered the same question about the same reader
with 32768 and nothing compared the two.

Measured 2026-09-08 with LibreOffice Calc 26.2.5.2 headless, on workbooks
built outside this tool because this tool could not build them: 16384
columns come back whole, 16385 come back as 16384 with the last column
dropped, exit 0 and not one word on either stream. After the change our own
16385 column workbook behaves identically, and hits the requested size to
the byte.

The encoder needed no change - column() counts letters in base 26, so it
walks past XFD on its own.

rows times columns still cannot pass 2 million cells, MinBytes is computed
from a one by one sheet so it does not move, and a sheet of 64 columns or
fewer is byte for byte what it was. The site is regenerated for the two
lines that name the range.

The guard asks every registered format that declares columns, so a third
tabular format is covered on the day it arrives. It asks about the OFFER
rather than building the file, because building one costs twelve megabytes.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
textenc.Properties() becomes textenc.Axes(names...) alongside textenc.Names(),
the shape the archive package has had since the containers were unified. All
three text formats take both axes and call it with both, so the narrowing has
no dead call. It is there because the fourth format is already named and
cannot take both: an HTML document has to be UTF-8 by its own specification,
so the only encoding axis it could carry is the mark.

Two guards close a gap that was measured rather than suspected. Given md a
declaration of its own that agreed on kind, unit and default and offered one
encoding fewer, eleven guards stayed green while md went on writing utf-16be
and stopped offering it. Given bmp a width starting at zero, ten stayed green
while tfg formats printed "whole number of pixels from 0 to 20000" and
--set width=0 was refused with "it has to be between 1 and 20000" - a
declaration contradicting the program, caught only by the backstop in
imagedim.Value, which picturesides_test.go says a person cannot reach. A
person reaches it exactly when a declaration drifts.

The picture guard rebuilds each declaration from the parts a format supplies
rather than comparing outright, because the largest side, the default and the
sentence are the format's own and are supposed to differ - four of the ten
sentences are correctly different. Rebuilding covers a field nobody has
thought of yet, which a list of field comparisons would not.

The narrowing is by name rather than by value. No text format wants a
narrower set of encodings, and all ten picture formats call Width and Height
in pairs, so narrowing a value is what imagedim.Side already does and it was
built after ten different ceilings had been measured, not before.

Declarations are byte for byte identical: tfg formats --json hashes to
0b1361a7294ab5b71b6acd39f13c9c74effa0a6df215f241fc3989636836dfc7 before and
after.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@donislawdev
donislawdev merged commit dde2cd9 into main Sep 9, 2026
18 checks passed
@donislawdev
donislawdev deleted the format/narrowing-for-textenc branch September 9, 2026 06:58
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