1# Style23Conventions this repository actually follows, and the reasons, so that a change4that breaks one is a decision rather than an accident.56## The formatter is the authority78`gleam format --check src test` passes and is meant to keep passing. Nothing9here is exempt and nothing is annotated to be skipped, because `gleam format`10has no configuration and no escape hatch — there is no pragma that makes it11leave a region alone. A file that argues with it loses on whichever day someone12runs it.1314So the code is written to want what the formatter does. Where the two would15disagree, the shape of the code changes rather than the rule. Three of its16behaviours are worth knowing before writing anything it will touch, because17each one has already decided how something here is written.1819**It reflows a list of scalars to fill the width.** A list of integers written20as a grid comes back as a paragraph. It does *not* reflow a list whose elements21are themselves lists — those stay one to a line, however short they are. There22is no magic trailing comma; a comma at the end changes nothing, and a comment23inside the list pins nothing but itself.2425**It strips trailing zeros from floats.** `0.40` becomes `0.4`. A column of26weights cannot be aligned on the decimal point and should not be attempted; see27`score` in `difficulty.gleam`, where the four coefficients are simply written28out and the comment carries what the alignment would have shown.2930**A nested call in the last argument explodes every argument.** A constructor31whose final argument is a bare list literal keeps its other arguments hugged on32one line and hangs the list beneath it. Wrap that same list in a function call33and all seven arguments go one per line. Data tables are therefore written with34bare literals and any transformation happens at the reading end, not the35writing end.3637## Data that has a shape keeps it3839A board is a picture and is written as one. In `families.gleam` a packing is a40list of rows, not a flat list of cells, and every cell is a one-letter constant:4142```gleam43Family("classic", "CLASSIC", 4, 5, 1, 3, [44 [u, g, g, u],45 [u, g, g, u],46 [u, r, r, u],47 [u, s, s, u],48 [s, e, e, s],49]),50```5152`e` empty, `s` single, `u` upright, `r` recumbent, `g` goal. One letter rather53than a word because every cell has to be the same width or the rows stop lining54up, and a packing that does not line up is a list of numbers again. The values55are the shape codes `domain` encodes with, so this is a spelling of the wire56format and not a private one.5758The nesting is what survives the formatter, and `families.grid` flattens at the59point of use. Flatten one of these back out to save the `list.flatten` and the60next `gleam format` turns the board into a paragraph. That is the general rule:61**when a literal's layout carries meaning, give it a structure the formatter62already keeps, rather than a comment asking to be spared.**6364## Comments say why6566The code says what it does. A comment that repeats it is noise. What a comment67is for is the reasoning that cannot survive in the code: what was tried, what68broke, what the alternative was and why it lost.6970Written declaratively and without hedging. Not "we probably want to avoid this71because it might cause issues" but "activation waits for every page running the72previous version to go, so nothing is still reading what is being thrown away."73A reader should be able to tell a measured fact from a judgement, and neither74should be apologised for.7576A decision that has already gone wrong once gets the incident, briefly, because77that is the part nobody reconstructs: the version was a number kept by hand and78by the tenth deploy it had drifted. Numbers earn their place this way — prefer79the number and what it counts to an adjective.8081## Gleam decides, FFI executes8283Every `_ffi.mjs` file is named for the one platform gap it fills — 32-bit words,84font metrics, rounding, the pixel pipeline, the platform — and none of them85knows what a theme, a family or a rung is. Logic that could live in Gleam does.86An FFI file that starts making a decision is a sign the boundary moved and87should be moved back.8889## Names carry digests9091Everything under `/assets/` is fingerprinted, so a URL never holds different92bytes and two builds cannot contend for one address. Four things keep their93names on purpose and the reasons are in `tools/bundle.mjs`. Anything derived —94a cache version, an asset name — is computed from content rather than95incremented by hand, because a number kept by a person is a number that96eventually disagrees with what it names.9798## Commit messages99100A declarative one-line subject that states the idea, not the diff:101102```103The shell was written once, and once was not enough104```105106not `fix(sw): re-cache index.html on navigate`. The body is prose, wrapped, and107explains what was wrong, why it was wrong, and why the fix takes the shape it108does — the same job the comments do, at the scale of a change. Present tense.109No prefixes, no ticket numbers, no trailers.110111## Prose112113The `·` middot is never used. Em dashes are, and so are numerals: a figure with114a caption beats a sentence that describes the figure.