Skip to the page
Home Search
Reading

These start from your device’s own settings. Change one here and this browser will remember it for this site.

  • The drawings appear finished instead of drawing themselves on.
  • Darker ink, firmer rules, and the foxing lifted off the paper.
  • More air between the lines and between paragraphs.
  • Scales the whole sheet — the lines, the gaps and the measure — from whatever size your browser is already set to.
  • The first four also set the reading face, because they have a real italic. The rest change the headings and leave Newsreader to read.
Drawers
Two cohabitating modes

What is settled, and what is open

The reasoning, kept so the same question is not re-litigated in three weeks.

This page is the decision log, generated from DECISIONS.md in the repository rather than retyped from it. It exists so the same question is not re-litigated in three weeks, and it is public for the reason the register is: a decision whose reasoning nobody can read is a decision that will be made again badly.

What is settled, what is open, and the reasoning for each — so the same question is not re-litigated in three weeks.


Open Link to this section

Settled half: both are gone. sitemap and agent-skills were bare tokens in the RFC 8288 Link header in _headers, and RFC 8288 admits an extension relation only as a full URI. Verified against all 236 entries of the IANA link-relations registry, fetched on the day rather than remembered. describedby, alternate and license are registered and stay.

What is open is whether a gate should exist, because this fault has now shipped twice — once on Star Stuff, once here — and both times it was caught by a person recalling a note, not by a check. The header's own comment said "registered relation types only" while contradicting itself, so the file was not merely wrong but self-refuting, which is the failure mode this repo most often gates.

The obstacle is that the source of truth is a network resource and the default path of every gate here is offline. Three shapes, none obviously right:

The second is the likely answer and would live in check-cache.mjs, which already parses _headers — a second parser for that file would be the check-markup.mjs entity-table drift arriving again. Not written, not measured.

The transferable lesson stands regardless: sitemap reads as standard and is not. Verify a relation against the registry before adding one — it is one curl.

The empathy study is a 2024 article with a 2023 DOI, and the accepted manuscript is not quotable (2026-09-10) Link to this section

The paper the proposed Sheet No. 10 rests its fairest reading of Schalk on. Ryan put the accepted manuscript in the SKS inbox and then the version of record beside it, which is what made the comparison below possible. Settled; nothing here blocks the sheet.

The citation, from the article itself and corroborated in two independent libraries — Crossref's publisher-deposited record and the NLM's PubMed entry, PMID 39371354:

Kimber, Lesley, Diarmuid Verrier, and Stephen Connolly. "Autistic People's Experience of Empathy and the Autistic Empathy Deficit Narrative." Autism in Adulthood 6, no. 3 (2024): 321–330. Mary Ann Liebert, Inc. doi:10.1089/aut.2023.0001

76 autistic participants. Three authors, and the first is Lesley Kimber — the accepted manuscript in the inbox is filenamed for the second, which is how a paper acquires the wrong short name.

The publisher is Mary Ann Liebert, Inc., which is what the article's own first page says. Crossref now returns SAGE, because SAGE acquired the journal after publication. Cite the imprint on the artefact, not the current rights holder — the same reasoning that makes a sheet name the printing it read.

THE ISSUE YEAR IS 2024 AND EVERYTHING CONVENIENT SAYS 2023. The DOI slug is aut.2023.0001; the accepted manuscript's deposit record at Sheffield Hallam's archive cites "(2023)". A citation built from either is wrong by a year and looks perfectly well sourced.

Second instance of a pattern, which is why this is an entry and not a note. The first was Experiences of autistic joy, recorded below: 2025 was its online-first date and the issue was 2026. Online-first year is not issue year, and a DOI slug is not a date. Both were caught only by going to a bibliographic database instead of reading the year off the artefact in hand. A paper newly cited on this site takes its volume, issue, pages and year from Crossref or PubMed — not from the PDF, not from the DOI, and not from a repository deposit.

The four passages the sheet wants, verified in the version of record, with pages:

passagepage
"Notably, there was a high proportion of hyper-empathic experiences…" — the abstract's Results321
"Seventy-eight percent of participants responded yes to the yes/no question…"325
"Often, this sense of distress was somatized…" and the four participant quotations325
"As yet, however, there has been limited theoretical and empirical work looking at this as a specific phenomenon worthy of study in its own right."326

The last is the sentence the sheet leans on hardest — the evidence that in 2018 Schalk was reading a literature that had not caught up with what Autistic people already knew about themselves. Identical in both states of the paper, and it carries a superscript reference to intense world theory, which the sheet can follow.

THE ACCEPTED MANUSCRIPT IS CORROBORATION AND MUST NOT BE THE SOURCE OF ANY WORDING. It is the authors' pre-copy-edit text, in British spelling; the published article is in US spelling and was edited past orthography:

accepted manuscriptversion of record
abstract, Results"additional labour… non-autistic centred world""additional labor… non-autistic centered world"
abstract, Methods"thematically analysed… amongst respondents""thematically analyzed… among respondents"
abstract, Background"over the last decade… in favour of""over the past decade… in favor of"
abstract, Conclusion"but to better bridge the gap""but also better bridge the gap"
the somatic finding, p. 325"was somatised""was somatized"

The Conclusion row is the one that matters, because it is not a spelling convention — it is a different sentence. Anybody who assumed the two states differed only in -ise/-ize would have quoted it wrong while feeling careful.

A correction to this entry's own first draft, which had a row wrong. The headline figure was written up as AM "Seventy eight" against VoR "Seventy-eight". The version of record is inconsistent with itself, and that is the real finding: hyphenated in the Results at p. 325, unhyphenated in the Discussion at p. 326, where the same figure is restated as "In total, seventy eight percent of participants indicated having experienced hyper-empathy". The copy-editor hyphenated one occurrence and missed the other. A sheet quoting both sentences must reproduce both forms and not tidy either, which is this house's ordinary rule arriving somewhere it looks like a typo.

The participant quotations carry no identifiers, and the sheet has to say so. They are set bare in parenthetical lists — "I feel physical pain in my body"; "I feel a horrible sensation in my body like my innards are being twisted" — with no pseudonym, number or demographic tag. The ledger elsewhere credits study participants by the names their paper gives them; here there are none to give, and silently anonymising people and being handed nothing to attribute look identical on the page. Say which it is.

No open-access or Creative Commons statement appears on the article, so the held PDF is a copy of a subscription article and belongs in SKS raw/ rather than anywhere this site serves.

A Readwise export runs on into an appended preview, and a quotation came out under the wrong Butler novel (2026-09-10) Link to this section

Found while researching a proposed Sheet No. 10 on hyperempathy, reading Octavia E. Butler through Sami Schalk's Bodyminds Reimagined. A tooling fault rather than anybody's transcription — Readwise syncs highlights off the device and nothing in this repo's brief was typed by hand.

Ryan's Kindle file for Parable of the Sower, ASIN B008HALO4Q, carries a publisher's preview of Parable of the Talents after the novel ends, and the export does not mark the join. Highlights run to location 5541. Location 4758 is "Then we buried our dead and we planted oak trees… decided to call this place Acorn," the last line of Sower. Everything after it is the preview: Jarret and Christian America, Asha Vere on her mother's god, Acorn's tool-making, the funeral verses. Readwise files a whole export under the title of the file, so highlights from two books arrive under one heading.

The visible symptom is a page number that stops counting. The reader shows "Page 330 of 330" at 85% of the file, because the print-page map covers Sower only and then runs out. A citation taken off that screen reads Parable of the Sower (p. 330) for a passage that is not in Parable of the Sower.

The quotation, re-titled:

Hyperempathy syndrome is a delusional disorder, after all. There's no telepathy, no magic, no deep spiritual awareness. There's just the neurochemically-induced delusion that I feel the pain and pleasure that I see others experiencing. Pleasure is rare, pain is plentiful, and, delusional or not, it hurts like hell.

Octavia E. Butler, Parable of the Talents — not Sower. Location 4839 of the Sower file, in the passage where Lauren is 23 and dreaming of a family whose pain no longer reaches her, on the same page as "They refused to let me be handicapped" and "So why do I miss it now?" The chronology settles it independently of the location: Sower ends in 2027 with Lauren at 18, and she is 23 here.

p. 330 WAS NOT A PAGE NUMBER, AND IT DID NOT TRAVEL WITH THE NEW TITLE. It was the exhausted Sower page map reporting its own last page, so it named a page of the wrong book. Re-titling alone would have left a citation wrong in a harder way to catch than the one it replaced — right book, plausible number, no relation to the text. A preview has no pagination of its own, so the page had to come from elsewhere.

Settled: the passage is at Parable of the Talents p. 9, confirmed off the standalone edition, ASIN B008HALPHC — page 9 of 394, at 1% of the file, under a running header that says PARABLE OF THE TALENTS. It is the second page of the novel, in Lauren's opening dream. The full citation is Parable of the Talents (p. 9), and the quotation runs longer than the brief had it:

Nevertheless I used to feel every damned bruise, cut, and burn that my brothers managed to collect. Each time I saw them hurt, I shared their pain as though I had been injured myself. Even pains they pretended to feel, I did feel. Hyperempathy syndrome is a delusional disorder, after all. There's no telepathy, no magic, no deep spiritual awareness. There's just the neurochemically-induced delusion that I feel the pain and pleasure that I see others experiencing. Pleasure is rare, pain is plentiful, and, delusional or not, it hurts like hell.

So the sheet reads both Parable novels, as Schalk's chapter does, and every quotation taken from the Sower file past location 4758 needs its title and its page checked before it is mounted. The other five quotations in the brief are Sower's and are unaffected.

An open item for a session in the SKS repo. Not to be fixed from here. highlights/Books/Parable of the Sower.md holds preview highlights from location 4839 to 5541 under a Sower heading. highlights/Books/Parable of the Talents.md is a separate export from a separate file, so the two are not duplicates and the misfiled block cannot be recovered by merging them — the overlap is partial and the location scales differ. Anything on stimpunks.org or in Helen's sites that cites this file past that boundary wants the same check.

The general shape, which is the part worth keeping. An appended preview is a second work inside one file, and every tool in the chain treats the file as the unit: the reader's page map, the export's title, the highlight's location. A citation is only as good as the assumption that one file is one book, and that assumption is silently false at the end of most ebooks sold today.

Which text of the biological-conscience passage, and it is an edition question rather than a verification one (2026-09-10) Link to this section

Correcting a wrong framing this session shipped first. The brief's six Butler quotations were checked against inbox/Butler, Octavia - Parable of the Sower.pdf and three of them could not be found, which was written up as the quotations being unverifiable. The fault was in the copy on disk. That PDF is missing chapters 9 and 21 of 25, at 85,034 words, and is OCR-damaged besides: em-dashes arrive as Ñ and as --. Chapters 9 and 21 are where the three missing passages live. It is not a usable verification copy and should not be reached for again.

All six quotations are verified against the Kindle edition Ryan reads, from the pages themselves. And the transcription route matters here: Readwise highlights are synced from Kindle, not retyped, so a divergence between one of them and a scholar's rendering is not a question about our copy.

The divergence that remains is between Butler's text and Schalk's quotation of it.

clauseButler, Kindle edition, p. 115Schalk, quoting Sower 115
the first"They could kill if they had to""They would kill if they had to"
the second"But if everyone could feel everyone else's pain""But if everyone else could feel everyone else's pain"

And a third, at Sower 12: the doctors call it an "organic delusional syndrome" in the text and an "organic delusion syndrome" at Schalk p. 88.

Ryan's reading is that these are edition differences, and it is the right default: the novel has been set by Four Walls Eight Windows in 1993, by Warner, and by Seven Stories since, and this house has now twice found a real textual difference between printings where it expected a transcription slip — Woolf's 1926 against her 1930, and Rossetti's colon.

One piece of evidence cuts the other way and is worth writing down rather than rediscovering: the pagination agrees. Both land the passage on page 115, and a Kindle page map is keyed to a specific print setting. Two printings that agree on where page 115 falls are more likely to be the same setting than to differ in three words of it. That is suggestive and not conclusive — a page map can be built against a printing nobody in this conversation is holding.

Either way the practical answer is the one this repo has already reached twice, under Which edition a sheet reads, when the work was revised: name the printing on the label, quote only from it, and make the difference a section of the sheet where it is interesting. Here it is interesting. A quotation that drifted by two words inside an otherwise scrupulous reading of a novel about feeling other people's pain accurately is the site's own subject arriving in the apparatus.

What is not settled, and what it changes. Nothing in the sheet's argument. The clauses in dispute are not the ones the sheet turns on, and "A biological conscience is better than no conscience at all" is identical in both. It is a label question and a possible third instance of the edition pattern, which would make that pattern a rule. Settling it needs one look at a 1993 or Seven Stories printing, which nobody here has.

A third fault in the imported overlap gate: a closed details reads as text on text (2026-09-11) Link to this section

Fixed here; recorded because Star Stuff is not edited from this repo and its copy has the same blind spot.

check-overlap.mjs walks text nodes and calls hidden() on each, which tests display:none, visibility:hidden and opacity:0 plus a declared list of visually-hidden selectors. None of those describe a closed details. Chrome reports the element's own height as the summary alone — 45px — while its children keep full-height rects that lie across whatever follows. The first details ever placed inside a landmark here produced 22 phantom collisions, 10 on Letter and 12 on A4.

It cannot surface on screen, which is why it went unnoticed in two repos. reveal.mjs opens every closed details before the screen pass and undoes it before the paper passes, so the closed state exists only on paper — the medium this house has already been burned by and the one Star Stuff's copy does not measure at all.

The fix is one loop in hidden(): a node that is a non-summary child of a details without open is not painted, on any medium, in any engine. That is the HTML spec rather than a style heuristic, which is what earns it a place beside a declared selector list rather than being the kind of sniffing the gate's own comment refuses.

Proved in both directions before it was believed, per the house rule:

A print stylesheet must not force the content visible, and that is now the load-bearing constraint rather than a preference. Forcing it would paint text this rule skips, turning a false-positive fix into a genuine blind spot. Sheet No. 11's content warning therefore prints its keyword list and not its detail — the keyword half is built to stand alone.

An open item for a session in the SKS repo: the library's index holds a third of a book, silently (2026-09-11) Link to this section

Not to be fixed from here. pdftotext extracts 299,336 words from raw/The Unabridged Journals of Sylvia Plath - PDF Room.pdf. The qmd extraction at .qmd/library/The Unabridged Journals of Sylvia Plath - PDF Room.pdf.md holds 109,718 — about 37% — and ends mid-word, part-way through the 1956 material.

The consequence is a false negative that reads exactly like a real absence. Searching the library for the "two electric currents" passage returns nothing. The passage is in the book, on p. 404. Nothing in the result distinguishes we do not hold this from we hold it and cannot see it.

That is the failure tools/sks-search.sh already has a long header about — a silent empty result being worse than a crash — arriving one layer below the wrapper, in the index the wrapper protects. The wrapper checks that an index exists. It cannot check that the index is complete.

For a session in that repo: find out whether the truncation is a page cap, a timeout, or a size limit in the extractor; check the other large PDFs in raw/ for the same shape (a file ending mid-sentence is the tell); and consider whether qmd can report extracted-versus-expected length so a short extraction is visible rather than silent.

A second case, found the same day, is the absolute form of it. inbox/Kurt Cobain - Journals.pdf is a photographic facsimile of handwritten notebooks — 76 pages, each a 2×2 spread, so about 300 notebook pages — and it has no text layer at all: pdftotext returns zero words. The library can never find anything in that book, by any search, ever. No re-extraction fixes it; it would need OCR, and OCR of handwriting is a transcription with a confidence interval rather than a text.

So the two cases want the same thing and it is not a better extractor. A file whose extracted length is implausible against its page count or byte size should be visibly flagged as unsearchable, so that an empty result can be distinguished from an absence at the point of searching. A facsimile in the library is a book we own and cannot grep, and that is a fine thing to hold — as long as nobody concludes from silence that we do not hold it.

And the library can be wrong in the other direction too, which is worse. raw/118363243-Vincent-van-Gogh-The-Letters.pdf is not the letters. It is a 19-page publisher's brochure for the 2009 six-volume Van Gogh Museum edition — slipcase, 2,180 pages, €395, launch price €325 until 3 January 2010. It indexes, it searches, and it answers to the name of the book. Beside it, raw/lettersofvincent0000jvan.pdf is Volume II only of the old three-volume English edition: letters ~100 to 695, the Hague and Nuenen years, nothing after 1885. Neither can reach Saint-Rémy or Auvers, and the filenames say otherwise.

A truncated extraction hides something we hold. A brochure filed under a book's name offers something we do not. The first makes a researcher give up; the second makes them cite air. Both argue for the same small discipline at ingest: record what a file actually is — edition, volume, coverage — rather than what its filename claims, and make an implausible extraction visible. The sheet that prompted this read its Van Gogh primary at vangoghletters.org in the end, which is free, complete and authoritative, and which neither of these files is.

An open item for a session in the SKS repo: two attributions on stimpunks.org (2026-09-11) Link to this section

Not to be fixed from here. Both found while researching a proposed sheet on Van Zandt, Van Gogh, Plath and Cobain.

One: a Disabled writer's byline absorbed into an anthology title. stimpunks.org/philosophy/do-you-know-why-we-have-the-sunflowers quotes the "word mines" / "tornado in my head" / "artists don't have to suffer for their art" passage and credits Disability Visibility: First-Person Stories from the 21st Century, linking the Disability Visibility Project.

The passage is Shoshana Kessock's, from "Falling/Burning: Hannah Gadsby, Nanette, and Being a Bipolar Creator" in Alice Wong's anthology (Vintage, 2020). Kessock published it first on her own site on 12 July 2018, at a URL whose slug is falling-burning-hannah-gadsby-nanette-and-the-myth-of-the-mad-artist; all three passages were confirmed there on 11 September 2026. Crediting the book rather than the writer is the mildest form of the failure this repo is organised against, and it lands on an essay about being a bipolar creator.

Two: a journal entry cited to a biography page. stimpunks.org/glossary/bipolar gives the "two electric currents" passage and credits the Poetry Foundation's Sylvia Plath page. It is a journal entry with a date: The Unabridged Journals of Sylvia Plath, Friday, 20 June 1958, read on the page on 11 September 2026.

And the wording was open for about an hour, then settled — against us, twice. Our page has "despairing negative—whichever". Checked the same day across three copies: the SKS PDF on the page, the Kindle edition of Kukil, and archive.org's search-inside of the print edition, which returns exactly one result for the phrase "which ever" — the June 20 entry, at p. 395.

The correct citation is The Unabridged Journals of Sylvia Plath, ed. Karen V. Kukil, entry of Friday, 20 June 1958, p. 395 — not a Poetry Foundation biography page.

One methodological note worth keeping. This was catchable only because the first copy consulted rendered every dash in the book as a hyphen, which made its punctuation obviously untrustworthy and forced a second and third look. An edition that quietly normalises is more dangerous than one that obviously mangles: the mangled copy announced itself, while a tidy one would have agreed with our page and closed the question.

An open item for a session in the SKS repo: two glossary pages splice two Butler passages into one quotation (2026-09-10) Link to this section

Not to be fixed from here. stimpunks.org/glossary/canary and stimpunks.org/glossary/very-grand-emotions each present this as a single blockquote under a single citation to Parable of the Sower:

I wish I could find other people who have it, and live among them. A biological conscience is better than no conscience at all.

Maybe it's like my sharing: One more weirdness; one more crazy, deep-rooted delusion that I'm stuck with. I am stuck with it. And in time, I'll have to do something about it.

The two are not contiguous and they are in the wrong order. "A biological conscience" is Kindle loc. 1565, about p. 115; "Maybe it's like my sharing" is loc. 350, about p. 26 — roughly ninety pages earlier.

The splice changes the meaning. In context, Lauren is comparing her emerging Earthseed conviction to her hyperempathy: the "one more weirdness that I'm stuck with" is the religion, and hyperempathy is the thing she measures it against. Spliced onto the biological-conscience line, it reads as though the weirdness she is stuck with is the conscience itself. Verified against the inbox PDF, chapter 4, which does hold this passage.

Every word is Butler's, every sentence is exact, and the quotation says something Butler did not. That is the tightened-source failure this repo is organised against, living on our own site.

Paths, for a session in that repo: site/stimpunks.org/glossary/canary.md lines 312 to 318, site/stimpunks.org/glossary/very-grand-emotions.md lines 76 to 82, and the live pages behind them. Queering Earth must not inherit the splice — a sheet that wants either passage quotes them separately, each with its own location.

One source on Sheet No. 9 is still at one remove (2026-09-10) Link to this section

Claude Lévi-Strauss on the floating signifier. Quoted inside Deleuze (pp. 64–65), so the words are credited to Lévi-Strauss on Deleuze's authority and not on ours. The primary is his 1950 introduction to the work of Marcel Mauss, not read here. It weakens no credit; it would strengthen the evidence, and the sheet says so in its own untidy block rather than leaving it here.

Closed the same day: Asasumasu's post was read in place and is quoted. It was mounted described rather than quoted, on the grounds that it had reached us through Helen's glossary. Ryan asked for it to be read and quoted, which was right — a sheet about coiners losing their coinages should quote the coiner in her own words, and hers turn out to make the sheet's own argument better than our paraphrase did: she explains the coinage as an act of widening because the words in use had no room for more ways of having a brain, and then defends the emptiness as the specification. Two things came out of reading it that a description could not have produced: the post is signed Neurodivergent K and not Kassiane Asasumasu, and Tumblr publishes no absolute date for it. Both are recorded in ATTRIBUTIONS.md and on the sheet.

Closed 2026-09-10, and it did not go the way an open question usually goes. Ryan asked for the 1898 Academy article to be found. It was: the Internet Archive has the issue, openly, and Holiday's account of the veto is on p. 129. Reading it did not confirm the sheet's unverified report — it corrected it. The circulating version has Carroll rejecting the drawing as <q>inadmissible</q>; Holiday wrote that Carroll called it <q>a delightful monster, but that it was inadmissible</q>. He liked it and refused it anyway. The three missing words are the difference between distaste and deliberate protection of an emptiness, which is the sheet's subject, so the sheet gained an argument rather than a footnote.

What remains unread: Anne Clark's biography, pp. 196–97, which Wikipedia cites for the veto and which nothing now depends on; and the 1932 first publication of the refused drawing, of which no public-domain copy was found.


The wordmark and the tagline Link to this section

The masthead currently reads Queering.Earth with "Post-normal possibilities." under it. Both are provisional.

The tagline is Helen Edgar's own phrase from the founding brainstorm, chosen because it is short and it is ours. The attribution question it raised is settled — the home page credits Nick Walker in prose, see below. The wording of both wordmark and tagline is still open. It replaced the working tagline — "Subverting, defying, disrupting, and liberating oneself from all forms of normativity (props Nick Walker)" — which is a paraphrase of Walker wearing his name. See ATTRIBUTIONS.md for the full reasoning and for how the page handles Walker now.

Changing either is one line in index.html. Whatever replaces them, the paraphrase problem does not come back: quote him exactly, or write our own line.

.qe-wide narrows on paper and widens nothing on screen, and whether the provocation should break the measure Link to this section

Found 2026-09-09, while deriving the drift rail's breakpoint. Not fixed, on purpose.

queering.css carried a note saying two blocks break the measure — the masthead and the provocation. It was wrong twice over. The masthead has never carried the class at all, and .qe-wide is a child of main, main is max-width: 34rem, and a max-width of 46rem inside a 34rem parent constrains nothing. Measured on screen: main is 544px, .qe-wide is 448px, exactly the content box every other block gets.

"It does nothing" was then the overcorrection, and it went out in three commits before anybody checked paper. @media print sets main { max-width: none }, so on a printed sheet this rule is the only thing holding the provocation in — it caps a block that would otherwise run the full width, and centres it. The class does not widen; on the one medium where it is live, it narrows. Measured by reproducing the print condition:

printable width.qe-widea sibling blockeffect
717px — A4 at Chrome's default margins717px717pxnone
739px — Letter, same736px739px3px
816px — Letter at zero margins736px816px80px

So its effect scales with the printer's margins and is invisible at the defaults, which is why nothing looked broken and why nobody can miss a block that was never wider. It surfaced only because the rail's breakpoint arithmetic reserved 288px of margin for it.

The lesson is the one this repo keeps relearning, arriving from a third direction: the first claim was reasoned from a rule, the second was measured on screen and generalised to every medium. check-contrast.mjs and check-overlap.mjs both measure paper separately precisely because paper is not a wider screen.

Three ways out, and this is a design question rather than a defect to sweep up:

  1. Make it real on screen — width: min(46rem, calc(100vw - 2 * var(--qe-gutter))) with negative margins, or move the constraint off main. The provocation would then genuinely break the measure, which is what the note claimed all along. This changes how every page looks, and the rail's clearance would have to be re-measured against a block that finally is 736px wide.
  2. Delete it, on the grounds that the site has looked right without it for its whole life and the measure is the design — accepting that the provocation then runs the full width on paper like everything else.
  3. Keep it and describe it honestly as the paper-only narrowing rule it actually is.

Ryan took 3 on 2026-09-09: the note now matches the code, and the code is unchanged. Option 1 stays available and is a separate, deliberate design change.

The rail's breakpoint is measured against what actually renders rather than against the rule, which is the right way round regardless of which way this ever goes.

Whether Helen gets a static CMS Link to this section

Deferred, with a named trigger. Not now, for three reasons:

  1. The design intent — queering the zine itself, playing with graphic font layout, each piece interpreting its own subject — is what a CMS structurally cannot hold. A CMS earns its cost when content is uniform and layout is fixed. Here the layout is the argument.
  2. Netlify Identity's git-gateway is being sunset, so Decap or Sveltia means standing up GitHub OAuth ourselves, writing a schema for a content model that does not exist yet, and adding a build step to a site that has none.
  3. The zero-cost path already works: Helen edits files in the GitHub web editor, opens a pull request, and Netlify posts a deploy preview URL on it. Struck 2026-09-12, on Ryan's word: nothing that requires GitHub or editing HTML works for Helen, and this reason had been false for as long as it had been written. Star Stuff runs 192 pages that way, which is where the sentence came from — it was carried over as a fact about this collaboration without being checked against the person in it. Reasons 1 and 2 stand on their own and the deferral survives, but it now rests on two legs rather than three. See A draft is reviewed at a real address below for what replaced it.

The trigger: the first repeating, uniform content type — a series where every entry has the same sections in the same order. Then Sveltia CMS, and not before.

The question still worth asking Helen: is the friction publishing, or authoring? If she writes prose and a session builds the artifact around it, no CMS touches that problem. Half-answered on 2026-09-12: the tooling is the friction in both directions. Reviewing is now solved without a CMS and without an account. Authoring is still open, and is the half the trigger above is really waiting on. Answered 2026-09-13, and not by a CMS: Helen contributes through a Claude Code session, which is exactly the case this paragraph named — she writes prose, a session builds the artifact, and no CMS touches the problem. Reasons 1 and 2 and the trigger are all untouched. See Helen contributes directly under Settled.

Which edition a sheet reads, when the work was revised Link to this section

Opened by the Woolf verification below, and it is a real design question rather than a pedantic one.

On Being Ill exists in two authorial states. Woolf published it in The New Criterion in January 1926 and revised it for the Hogarth Press edition of 1930, which she and Leonard printed and hand-set themselves. The revisions are not typographical. In the first paragraph alone she changed "brings to light" to "brings to view," "uprooted in us in the act of sickness" to "by the act of sickness," cut "and infinitely more," and opened out two lists from commas into her own and…and…and:

1926, The New Criterion1930, Hogarth Press
with love, battle, and jealousywith love and battle and jealousy
is null, negligible and non-existentis null, and negligible and non-existent

So the label's "date of the original" is not one field for a revised work. A sheet that mounts On Being Ill is mounting one of two texts, and the date, the wording, and the publisher move together. Three ways to handle it and none is obviously right yet:

  1. Name the edition on the label and quote only from it — the cheapest, and it makes the choice visible instead of silent.
  2. Read the revision itself as the subject. A writer opening her commas into and…and…and between one printing and the next, four years later, in type she set with her own hands, is a queering of her own sentence. That is a sheet, not a footnote.
  3. Show both, side by side, and let the reader do the work. Riskiest to lay out, most honest to the material, and the most "no hard facts for everything" of the three.

Worth settling with Helen, because it decides what the Woolf sheet is.

A second sheet has now hit the same question, 2026-09-08. promises-like-pie-crust.html mounts Rossetti's Promises like Pie-crust, whose 1896 first printing has a colon at line 20 where every circulating copy has a full stop. Both sheets ended up doing 1 and 2 together: name the printing on the label, quote only from it, and make the difference between printings a section of the sheet. Two for two is a pattern, not yet a rule — but the next sheet that reads a revised or posthumously-printed work should assume this is the house answer unless Helen and Ryan decide otherwise, and option 3 (both texts side by side) still has no worked example.

Rossetti's case adds a wrinkle Woolf's did not have. Woolf revised her own text, so both states are authorial and the question is which of her two you mean. Rossetti died before the poem was printed at all: the 1896 text is her brother's transcription of her notebook, so the earliest printing is not certified to be her hand, and the sheet has to say so rather than resting the finding on "the older text wins."

Three quotations on More Realms, checked because a sheet reused them (2026-09-09) Link to this section

Not ours to fix, and now specific enough to be fixable. The open Woolf item that stood here since 2026-09-08 said "ours to check against the book before any sheet reuses it." Sheet No. 8 reuses it, so it got checked, along with everything else on the page it follows. Ryan supplied A Room of One's Own and The Letters of Emily Dickinson; the results split three ways.

1. Woolf's "resonant and porous" — the wording is right. Closed. Verified in the book (chapter VI, pp. 148–149, Hogarth 1929). The phrase is Woolf's, the ellipsis is honest, nothing was tightened. The only fault was citing it to Popova rather than to Woolf, and our sheet cites the book. One nuance we kept and she may want: the sentence is Woolf guessing at what Coleridge meant, and it is hedged twice — "Perhaps the androgynous mind…", "He meant, perhaps…". Quoting from "the androgynous mind is resonant and porous" quietly promotes a speculation to a definition.

2. The Mary Oliver epigraph is in the wrong book and is trimmed. Open, hers. It appears on at least two More Realms posts (Monotropa Uniflora and Monotropism, Mossy Minds & Monotropism) and on autisticrealms.com, as "Attention without feeling, is only a report." — Mary Oliver, Upstream: Selected Essays (2016). It is not in Upstream; Ryan owns it and looked. It is in Our World (Beacon Press, 2007), and the full passage is "Attention without feeling, I began to learn, is only a report. An openness — an empathy — was necessary if the attention was to matter." Three words gone from the middle, and the whole second sentence gone — the sentence that says what attention needs instead. The quotation as it circulates states the problem and drops the answer. Full working in ATTRIBUTIONS.md.

3. The Dickinson letter has drifted three characters. Open, hers, and very minor. Against Letter 997 in the Letters: a dash where there is a full stop, child for Child, and an inserted the in "enhances the mystery". Nobody did it on purpose; it is what happens to a quotation copied from a copy. It is worth a line only because the sheet's subject is that Dickinson's punctuation and capitals were regularised by her editors, and this is the same drift, on the same writer, in a friendly source, in 2026.

Where these live, for a session in the More Realms repo: site/morerealms-com/posts/monotropa-uniflora-and-monotropism.md, site/morerealms-com/posts/mossy-minds-monotropism.md, site/autisticrealms-com/posts/mossy-minds-monotropism.md, and the "resonant and porous" citation also appears in neuroqueering-time-bergson-deleuze-and-monotropism-an-exploration.md on both her domains. Never edited from this repo.

Two lists at the foot of the home page, not one Link to this section

The home page's back matter is the pages that are not specimens. They divide in two, and the first version of this note got it wrong by putting everything in one list.

Purpose above plumbing, both at the foot of the page, both bare-tier dls.

THE SPLIT IS PRECEDENTED, NOT INVENTED. Star Stuff already made it: What this project is holds mission, manifesto, six-principles-and-a-room and inclusion-safety-creed; How it is made, and how it is checked holds privacy, design, changelog and print-design. Our existing list maps onto that second group one for one, privacy included. Ryan raised the question, the shelf had already answered it.

Four names were considered and all four refused, for reasons worth keeping so the question is not reopened from scratch:

The founding papers is archive vocabulary for an institution's charter documents, which is what a mission and a manifesto are, and it is parallel in shape to The cabinet itself so the two read as a pair.

The mission page is an index of aims, not an argument (open until it is written) Link to this section

The home page already carries 611 words of manifesto — #queering-is-a-verb (215), #to-queer-is-to-adapt (278), #the-type-plays (110) — plus 118 in #what-this-is. A mission and a manifesto written from scratch would restate most of it, and two copies of the same words drift is the rule this site repeats more than any other.

The genre is the fix, and Star Stuff found it: its mission page is eleven aims, each one linked to the page where that aim is already being kept. An index of commitments with receipts cannot duplicate an argument, because it is not one. Ryan chose this over moving the manifesto sections off the home page, so the home page keeps its argument unchanged.

Much of the material already exists and is already checkable — cite to the primary (ATTRIBUTIONS.md, every provenance line), publish the corrections (/changelog), never an image of text (/design, enforced by check-contrast), make no third-party request (/privacy, enforced by check-metadata). An aim with no page keeping it is the interesting case, and the ones that turn up when the list is drafted are worth arguing about rather than quietly dropping.

What a new entry in either list costs: a <dt>/<dd> pair in index.html, a slug in the right group in tools/pages.mjs, and the ordinary new-page checklist — a register entry with its data-sheet, a social card, a JSON-LD block, a redirect rule, a sitemap line, a regenerated Markdown sibling. No plate number, no accession stamp, no provenance line: those are for specimens. The lists derive nothing, on purpose — those sentences are authored, and queering.js may not write words.

Still open: whether either section keeps a prose intro once it holds more than four entries.

The Playful Manifesto quotation on stimpunks.org wants fixing there Link to this section

Not this repo, and not editable from here. The Neuroqueer Learning Spaces Manifesto quotes Max Alexander as "a translation of my world into yours….This is a protest". The primary reads "a translation of my world to yours", and three sentences stand between that one and the protest.

One preposition and an undeclared elision — the exact size and shape of the failure ATTRIBUTIONS.md exists to catch, found in our own foundation's page while sourcing a quotation for /manifesto. It is a WordPress page Ryan can edit; recorded here rather than acted on, the same way SKS findings are.

The fix is one word and a fuller quotation, or the ellipsis marked as eliding three sentences. Neither changes the manifesto's argument, which is why it survived this long.


Settled Link to this section

A sync skill, and what a one-line file actually does in a merge (2026-09-14) Link to this section

Ryan: "I want to avoid git commands for Helen and I as much as possible. Create a sync skill for us to pull from GitHub and update our working directories. See the sync skill for Star Stuff if its helpful."

Settled: .claude/skills/sync/SKILL.md, ported from Star Stuff and rewritten in three places — because a port is a rewrite wherever the original encodes an assumption this site does not share, and Star Stuff has one branch where this has three kinds. The new step is merging main into a draft branch, where the generated files conflict and the regeneration is the resolution; the new prohibition is that nothing ever merges toward main, because the branch _headers carries X-Robots-Tag: noindex on /* and publication takes files; and the new trap named in the conflict step is that a .md is derived only if a page of that name exists, so resolving ATTRIBUTIONS.md as derived drops a draft's credit rows while every page still reads perfectly.

.gitattributes had to exist first, because the skill's conflict step was advice built on sand without it. This repository had none. Star Stuff added one the same week and for the same reason — it gained a second contributor — and both of its rules apply here: * -text, because the gates verify derived files by regenerating and byte-comparing and a per-platform line-ending rewrite would report every one of them stale on a tree nobody touched; and search-index.json -merge -diff, because it is 1.5 MB on one line.

AND THEN THE SENTENCE THAT JUSTIFIED THE SECOND RULE TURNED OUT TO BE WRONG, WHICH IS THE PART WORTH KEEPING. The comment inherited from Star Stuff's copy said git might "splice two JSON documents into one that parses and is wrong". That cannot happen to a file with no interior line boundaries — a three-way merge has nothing to interleave. Measured in a throwaway clone of the real divergence, then reproduced exactly on the real merge an hour later:

what git does
without the rulesays Auto-merging, writes conflict markers into the file, leaves 5 lines of invalid JSON
with the rulesays Cannot merge binary files, leaves the file one line of valid JSON (ours), conflict still flagged

So the rule does not prevent the conflict — it keeps the working file a usable index instead of a broken one, and -diff stops git rendering a 1.5 MB line as a diff. Both shapes need the same fix and neither is resolvable by reading. The rule is worth having and the reason on it was not the reason it was given.

Star Stuff's own .gitattributes carries the same unverified claim, on a 6.1 MB single-line index, and the same reasoning says it cannot splice there either. Recorded here rather than fixed there, because Star Stuff is not edited from this repo — the standing convention, and the third finding filed this way after the three faults in the imported overlap gate.

The bootstrapping asymmetry is real and is not a problem. The merge that delivers .gitattributes to a branch runs under the branch's old rules, so it gets the marker shape; every merge after it gets the binary shape. Watched happening on draft/time-present-time-past: Auto-merging search-index.json, 5 lines, 3 markers, exactly the clone's numbers.

Both branches were brought up to date the same afternoon, and the drafts base was the one that mattered. start-draft cuts every new draft from it, so while it sat three commits back every future draft would have been born stale — without .gitattributes, without the machines section in CLAUDE.md, without knowing sync exists. The draft branch itself needed it less than it looked: none of the three commits touched a page that draft renders, so nothing was stale for the reviewer — what was stale was the workshop.

Both branches fail check-sitemap and check-addresses afterwards, by name, and that is the design. review-practice.html and time-present-time-past.html are not in the manifest because they are not accessioned. All three rendering gates passed on the merged tree, which is the pass that matters when a merge can produce a tree neither person ever had.

Verified at the edge rather than assumed, because the whole hazard of the operation was one header travelling the wrong way: queering.earth answers with no X-Robots-Tag, and the draft deploy answers 200 with x-robots-tag: noindex.

Open: nothing gates branch freshness, and nothing gates the direction of a merge. tools/draft.mjs reports DANGER when a draft branch's _headers has no /* noindex, which covers a branch cut from the wrong base — but a merge toward main is caught by nothing except the capitals in CLAUDE.md and _headers. The live probe stays curl -sI https://queering.earth/ | grep -i x-robots.

One branch per draft (2026-09-13) Link to this section

Ryan's call, the same day the shared branch produced its third fault. Each draft now lives on draft/<slug>, cut from drafts. drafts becomes a base carrying only the branch furniture: the X-Robots-Tag: noindex block in _headers and review-practice.html.

The three faults are the argument, and none of them was a mistake anybody made. Two people's ledger rows conflicted in ATTRIBUTIONS.md on the day both drafts wanted entries. /ledger — a published page generated from that file — was left stale on the branch by one person's edit, so check-metadata failed for both. And publish-draft offered one person the other person's page and shared files, at the moment somebody is working a checklist and inclined to trust the tool. A shared branch produces these by construction. The instinct to write more careful rules for sharing was the wrong instinct; the branch was the thing to change.

The cut is from drafts and not from main, and that is the load-bearing detail. The noindex header cannot be scoped by host — _headers has no host matching and netlify.toml headers are not context-specific — so it lives as a branch-only edit. A draft branch cut from main would have no noindex, and its deploy would be a fully crawlable duplicate of the published site. Netlify deploys draft/* as a wildcard, which is why the prefix exists: one entry covers every draft branch, nothing is added when a draft starts and nothing removed when it is published, because deleting the branch takes the deploy with it. "All branches" is still refused — it would publish any stray branch crawlable. The wildcard leaves exactly one hole: a draft/… branch cut from main would deploy with no noindex. tools/draft.mjs guards it by reading each branch's own _headers for a noindex on the /* rule and reporting DANGER with the fix. That is a real test and not a string count, because main carries a /drafts/* noindex of its own.

It made the tooling simpler rather than more complex, which is the sign it was the right shape. scopeFor had grown commit archaeology — a file belongs to this draft if a commit that also touched this draft's page touched it — purely to disentangle two drafts on one branch. With one draft to a branch, scope is what differs from main minus the furniture, and the contested-file case cannot occur. Publishing then deletes the branch, so there is no re-sync step and no shared asset left in a draft state to conflict later.

Two faults found while rewriting it, both in the same fifteen minutes, both from the same habit of asking a slightly wrong question. git diff main...branch diffs the merge base, so it listed tools/make-whats-new.mjs — a change that had since reached main by another route and was identical on both sides. And a bare \.md$ rule for "derived" filed ATTRIBUTIONS.md as generated, which would have left a draft's ledger rows behind at publication, silently, with the sheet shipping and the credit missing. A .md is derived only if a page of that name exists.

The cost is one Netlify branch-deploy entry per draft, added when the branch is cut and removed when it is published. That is the price of the isolation and it is paid once per sheet.

A publisher's byline does not outrank a living author's name (2026-09-13) Link to this section

Ryan's call: never deadname anyone, including in citations of work published under a former name. Use the name the person uses. Settled, and it closes the open question that the Held, Not Fixed draft had been carrying on its own face.

What made this worth recording is that the site had already written the right principle and then broken it four times. ATTRIBUTIONS.md says, in as many words, that reproducing a publisher's record over a living author's own name is not neutral accuracy — it is a database outranking a person — and the entries around that sentence printed the old byline of the third author of the monotropism paper, on two pages and twice in the ledger.

The justification given was findability, and it does not survive inspection. The entries said we cite him as Wenn and state what the byline says, so the paper is findable without that cost. The DOI is what makes a paper findable. The old name was never doing that work, so the cost was being paid for nothing. Crossref and most citation managers still carry the 2005 byline, which is an argument for writing citations by hand here rather than generating them — not an argument for copying the database.

The form to use states the fact without the name: the journal's byline is not the name he uses. /two-cohabitating-modes had already found the graceful version by accident — a register label that reads and the journal's byline is not, stopping exactly where the old name would have gone.

Nothing gates this and nothing can. A deadname is not a shape a checker recognises; it is a fact about a person that only a person knows. It is an editorial rule in CLAUDE.md under House voice, next to identity-first language, and it needs somebody to hold it.

The zine setting was built, measured, and dropped (2026-09-13) Link to this section

Helen's first piece arrived as an A5 zine — numbered sections, monospace kickers, washi tape, a rubber stamp reading HELD NOT NAMED, running feet. The question was whether to keep that setting. It was built as .qe-zine and then removed on Ryan and Helen's joint call; Held, Not Fixed is a regular essay. Recorded here so it is not rebuilt from scratch by somebody reading the zine and having the same good idea.

What was established while building it is worth keeping even though the thing is gone.

Most of a zine setting really does work in both media, and only the pagination is print-only. Section rules, small-caps labels, tape and the specimen box were live on screen and on paper; break-before: page gave one section per sheet when printed. A page number is a fact about paper and a lie on a page that scrolls, which is the line between the two halves.

@page CANNOT BE SCOPED BY A CLASS. @page { size: A5 } applies to the document, so one in the shared stylesheet would have printed every sheet on the site at A5. Scoping it needs a style block in the page's own head. This is the reusable finding: any paged-media rule is site-wide by nature, and a per-page paper size is therefore a house question rather than a line of CSS. Chrome also does not support CSS margin boxes, so running feet were never available in a browser print regardless.

The monospace kickers could not come across and the reason is a standing rule. A component may mix the two type roles and may never name a family; exactly two things hardcode one, both the reader's own system face, both for a semantic reason, and a third added for looks retires the reasoning behind the first two. Small caps were used instead, on Ryan's call — with the unlooked-for benefit that font-variant-caps keeps the authored capitalisation in the DOM, so the Markdown and the finding aid get The shop rather than a shouted copy of it.

The HELD NOT NAMED stamp could not be .qe-stamp and never can be. That component means accession: the number is real or there is no stamp. A second stamp shape asserting a reading rather than recording an accession would make the real ones unfindable — the gold-seam failure, in the component that exists to prevent it.

The treatment never reached main, so dropping it un-shipped nothing. What survives on the sheet is one line in the label block: First set as: a zine, draft one, September 2026. That is provenance and it is true — the same fact the Woolf sheet records when it says where the essay was first printed.

The trigger for revisiting: a piece whose argument needs pagination, rather than one that merely arrived paginated. Nothing in Held, Not Fixed did.

Helen contributes directly, and the constraint that shaped this repo is routed around rather than overturned (2026-09-13) Link to this section

Ryan: "What's the best way to bootstrap Helen into direct contribution? I'd like to get her set up in Claude Code using this repo."

The sentence that decided the review path is still true and has stopped being load-bearing. Nothing that requires using GitHub or directly editing HTML is going to work for Helen struck reason 3 from the CMS deferral and built the whole drafts branch workflow. A Claude Code session requires neither thing: she says what a sheet is and which words are quoted, and the session writes the markup and runs the git. Nothing was overturned — the requirement was removed from the path rather than the person moved onto it, which is why the review layer survives intact below.

Settled: full parity, on Ryan's call. "She has full access, full power, same as me. Skills and anything else rewritten to consider us both." Both draft, both review, both publish, both run the sweep. Branch protection on main was offered and refused by that answer, and the refusal is consistent with how this repo already works: the accession checklist is a checklist rather than a permission, and nine gates that do not care whose hands ran them are a better guard than a GitHub setting that only knows a name.

What parity cost was wording, and the wording was doing real damage. The three draft skills addressed one operator by name — ask Ryan whether to publish it, tell Ryan it is Helen's link — which reads to a session as an instruction to go and consult somebody who is not in the room, on the machine where that person is the one typing. Rewritten to name the role: the collaborator who did not write the sheet is the reviewer, whichever of them that is. Dated records keep their names. On Ryan's call, 2026-09-11 is a fact about who decided something, and rewriting it would falsify this file the way renaming an old accession would falsify the register.

.claude/settings.json is the other half of the answer and it is not a convenience. A full sweep is four generators and nine gates; with no allowlist that is dozens of permission prompts in a row, which is the same tooling friction that decided the review path in the first place — the thing that loses a collaborator is never the hard part, it is being interrupted forty times on the way to it. Thirty-one commands, enumerated rather than wildcarded, in the pattern _redirects already uses so a missing one is reportable by name.

git push is deliberately not on the list. It is the one outward-facing, hard-to-take-back step in the workflow — the one that deploys to queering.earth — and one prompt per publish is not friction. Everything pre-approved is either a measurement or reversible in git.

The review layer's opening sentence needed correcting and the component did not. CLAUDE.md led that section with Helen reviews drafts, and neither GitHub nor HTML is a route she can use, which is now half-false. But the thing was never really about what a reviewer could not do: a draft wants a real address before it is accessioned, and feedback wants somewhere to go that is not a pull-request thread. Both are as true for a reviewer who could open a terminal as for one who would not.

The CMS deferral survives, and its open half closes without a CMS. Whether Helen gets a static CMS asked whether the friction was publishing or authoring, and half-answered on 2026-09-12 that the tooling was the friction in both directions. Authoring is now answered too, by the answer that entry predicted: if she writes prose and a session builds the artifact around it, no CMS touches that problem. Reasons 1 and 2 stand untouched — the layout is still the argument, and Netlify Identity is still being sunset — and the named trigger is unmoved: the first repeating, uniform content type, and not before.

ONBOARDING.md is the mechanism, because a guide nobody opens is a decision nobody acts on. It is written for the new collaborator and for the session beside them, so the commands in it are things to ask for rather than type. It is also the first document here addressed to somebody outside the two people who built the site, which is why it says what cannot be broken before it says what to do.

Open, and stated rather than hidden: nothing verifies any of this. No gate reads ONBOARDING.md, so a Node version, a gh flow or a renamed skill can rot there silently, and the guide's install path has not been walked on a second machine — it is reasoning about a clean Mac, not a measurement of one. The first real session is the test, and whatever it finds belongs back in that file the same day.

grep reports nothing, three times, because a tool here fences its placeholders with NUL (2026-09-13) Link to this section

tools/make-records.mjs contains eight literal NUL bytes, U+0000, fencing the code-span placeholders in inline() and mdText(). file therefore calls it binary data, and grep prints nothing rather than saying why. A plain grep -n 'const ' tools/make-records.mjs exits 1 with no output, which is indistinguishable from a file that does not contain the string. It cost a session three searches and a wrong theory about the file being corrupt before file was run on it.

The fence is right and is not the thing to change. A placeholder needs a delimiter no source text can contain, and this is a repository whose prose is about its own markup — every printable candidate is one an entry may legitimately write inside a code span, and the day it does, a placeholder is restored into the middle of somebody's sentence. NUL cannot appear in the Markdown, so the fence cannot be forged. The same reasoning already protects --qe-space-* from the emphasis stripper.

The cure is knowing, so: grep -a, and check file when a search comes back empty on a tool you can see the contents of. The note is at the mechanism in make-records.mjs too, but it is recorded here because the person this catches next will be grepping the repository rather than reading that file.

It bites an edit script as well as a search. The "spaces" around the placeholder index are NULs, so a pattern typed from what the terminal renders will never match — which is how the first attempt to teach that file strikethrough failed, on an anchor that looked character-for-character correct.

The gate ports are shared with Star Stuff, and two sessions on one machine collide (2026-09-13) Link to this section

This repo's Chrome gates bind 9412, 9413 and 9414, and so do Star Stuff's. The two repositories are checked out side by side, the gates were ported from there, and the port numbers came with them. A session working in each repo at the same time is two suites contending for three ports, which happened three times in one afternoon: a sweep hung for twenty minutes, and a later one had check-width.mjs refuse in 0.2s while a neighbouring check-overlap.mjs held 9414.

The refusal is cdp.mjs working exactly as designed and is not the fault. That guard exists because a gate spent five days silently measuring in an orphaned browser it did not launch; the port must be free before the spawn is what stops that, and it cannot distinguish an orphan from a live neighbour — nor should it, because driving either one is the same mistake. The twenty-minute hang is the part still unexplained, and it is the shape to watch: a gate that neither refuses nor finishes.

Not fixed, on purpose, and here is what was weighed. Renumbering this repo's ports would end the collision and is one line per gate — but it silently ends the protection too, in the one direction it has already paid off: an orphan left by a Star Stuff probe on 9414 is exactly the accident cdp.mjs was written for, and moving off that port means never being told. The collision is loud, correctly reported, and costs a wait. The alternative is quiet.

A PRE-FLIGHT lsof IS NOT THE ANSWER, AND THAT WAS WRITTEN DOWN WRONG FIRST. The first version of this entry advised checking the port before starting a sweep. It was tried in the same hour and it does not work: the ports were free, the sweep started, contrast and overlap ran their 55 and 42 seconds — and check-width.mjs refused, because the neighbour had taken 9414 in the seconds between the check and the spawn. The window is not the sweep, it is every moment until each gate binds, and no check outside the tool can close it.

What works is retrying the refused gate, which is cheap because the refusal costs 0.2s and is unambiguous. Width took twelve attempts at twenty-second intervals before it got a clear port, then passed. A sweep is not wasted by this: the other eight gates had already reported, and check-width.mjs alone is the one to re-run.

Wait rather than kill. A neighbouring gate is somebody's real run, not litter. Litter is a separate matter — around 200 stale /tmp/ss-* and /tmp/qe-* profiles are on this machine from interrupted runs in both repos. cdp.mjs removes its own on a clean exit and cannot on a kill.

Star Stuff is read-only from here, so its half of this cannot be changed from this repo — which is the other reason nothing was renumbered: a coordination problem fixed on one side only is a fix that one side remembers.

A converter that does not know a syntax publishes the syntax (2026-09-13) Link to this section

/what-is-settled had been showing ~~ fences as text since the day reason 3 of the CMS deferral was struck. make-records.mjs knew emphasis, code spans and links, and did not know strikethrough, so it passed the tildes through and the page printed them. On the page whose whole job is to show what was retracted, the retraction read as a typo.

No gate here could have caught it and none should. Every check reads structure — balance, order, colour, position, width — and this was valid markup saying the wrong thing in prose. It was found by reading the page, which remains the only instrument for this class of fault.

The tell is that it fails silently in exactly one direction. An unknown tag makes make-markdown.mjs throw, deliberately, because a dropped element is a Markdown copy that says less than the page. An unknown inline syntax has no such guard: the characters survive, so nothing is lost and nothing is converted, and the output looks like a plain-text file that forgot to become HTML. The converter now throws on an unclosed run rather than emitting a stray fence, which is the shape emphasis() already had.

A single tilde is not strikethrough, and this corpus proves it five times. ~100, ~60px, ~896px, ~108px, ~120 — approximately, in ordinary prose. The run has to be exactly two with GFM's flanking rule, and the round-trip proof had to be taught the same fence or it would have demanded text the converter was right not to produce. That is the trap mdText()'s own note already records about underscores: the proof has to model the converter, not approximate it, because a guard that cries wolf gets relaxed.

It is del and not a class. A line-through drawn on a span is invisible to a screen reader, so the one mark on these pages that says this is no longer true would be missing for the readers least able to infer it. The element carries the meaning and the colour only shows it — moss letters, coral strike, the colour on the rule and never on the word, which is .qe-correction-speaker del's idiom reused rather than restated.

The struck sentence leaves the search index, and that is correct. make-search-index.mjs skips del subtrees, because plain text has no vocabulary for this is what we got wrong and a snippet would surface a retracted claim as a current one. Checked rather than assumed: /what-is-settled still indexes that passage once, through the 2026-09-12 entry that quotes it as history and explains why it was struck. The retraction is findable; the retracted claim is not.

A correction made while a sheet was being mounted is not a correction since it arrived (2026-09-13) Link to this section

Found by reading /whats-new against the thirteen provenance lines, after an unrelated edit made one of them move. The listing said Sheet No. 9 had been Corrected twice since while the sheet itself said Not yet corrected, and those are the two views of one fact this house says must agree.

The count was right and the word was wrong. make-whats-new.mjs gathered every Re-determined and Label corrected entry filed to a page and reported the total under the word since. A sheet is routinely corrected while it is being mounted — a citation checked against the primary, a story everybody tells found to be wrong — and those entries are filed to the sheet like any other. So /wild-nights read Corrected four times since for four corrections made the day it went up, and five sheets read as corrected while their own lines said they were clean. Nothing was miscounted; the listing was claiming a chronology it had not checked.

The split is on the arrival day, and NOT on the mounting accession. The obvious key is the accession that mounted this page, and it is not a thing: /ledger has three Mounted accessions on the day it arrived and /gloomy-sunflowers two, because Mounted is the register's word for anything added to a page. The arrival day is a thing, because it is git log --diff-filter=A and already measured for the listing itself.

It is also the only rule a generator is entitled to here. Within one day the order of accessions is editorial and nothing can verify it — this file says so about the register's own ordering — so a tool that placed one same-day entry after another would be asserting a fact it does not have. /promises-like-pie-crust draws exactly that finer distinction in its own prose (four times on mounting, then corrected once more … when the plates changed, all seven on 8 September), and it is allowed to, because a provenance line is authored and knows which accession mounted it. The listing says the coarser true thing; the sheet says the finer one.

The four sheets reading Not yet corrected were right all along, and that is the part worth recording. The first reading of this fault was that they had drifted and needed mending. Measured, the opposite: an accession history reports what has happened to a sheet since it was accessioned, twelve of the thirteen lines were exactly right under that reading, and five of them go further and mention mounting-time corrections in their own words. A --mended seam forced onto those four would have been a gold join on sheets nobody had corrected — decoration asserting a fact, in the component this house built to make real mends findable.

One real drift, and it was the sheet. /on-being-ill never recorded the re-determination of 9 September, when a line of Woolf's turned out to be Woolf guessing at what Coleridge meant and the quotation was re-cut to start where the guess does. Its line said re-determined once against a register holding two. Thirteen lines, one wrong — which is a better result than the gate-shaped instinct predicted, and the reason to measure before mending.

Nothing gates this. The counts agree today because they were compared by hand. A check would have to know what a provenance line means in prose, which is the thing that is authored.

A draft is reviewed at a real address, and the review layer never ships (2026-09-12) Link to this section

Ryan asked for a lightweight way to publish a draft for Helen to review before it is published, and then supplied the constraint that decided it: "Nothing that requires using GitHub or directly editing HTML is going to work for Helen."

That sentence falsified a standing decision. Whether Helen gets a static CMS deferred partly on the grounds that the zero-cost path already works: Helen edits files in the GitHub web editor, opens a pull request, and Netlify posts a deploy preview URL on it. It had been false for as long as it had been written — carried over from Star Stuff, which does run 192 pages that way, as a fact about this collaboration that nobody checked against the person in it. Reason 3 is struck; reasons 1 and 2 stand and the deferral survives on two legs.

The problem splits, and only half of it was ever hard. Reading a draft never needed an account — a deploy URL is a URL, and a Netlify branch deploy gives a permanent one. Giving feedback was the whole difficulty, because a PR comment thread was the entire answer.

Drafts live at the root of a long-lived drafts branch. A drafts/ folder on main was the other candidate and it works mechanically: every generator and every gate here reads readdir(ROOT) non-recursively and check.mjs filters !c.includes('/'), so a subdirectory is invisible to all of it with no NOT_CONTENT entries to keep in step — which is better than the usual exclusion-list answer, since a second list is the drift this repo keeps warning about. It was refused for two reasons that are not about plumbing. It would put unreviewed attributions on queering.earth itself, unlisted but public and unauthenticated, which is precisely the exposure ATTRIBUTIONS.md exists around; and a page in a subdirectory needs ../queering.css, so it does not render what will ship and promotion becomes a rewrite of every asset href. On a branch the draft is byte-identical to the published page.

The failing gates on that branch are a feature. check-addresses names the missing 301!, check-card-order the missing card, check-sitemap the missing <loc> — the accession checklist, reported by name, on a page that is not supposed to pass yet.

drafts/review.js is three lines in one head block, and publishing means deleting them. Armed, every block grows a visible focusable Note control; notes live in localStorage and leave only through Copy my notes, which builds plain text carrying the section, a deep link to its authored anchor, the quoted line and the reviewer's words. No endpoint, no account, no third party — this site makes no third-party request and a review tool is not the place to start one.

IT WRITES WORDS, AND THAT IS A CARVE-OUT STATED RATHER THAN TAKEN. queering.js may never create words; queering-search.js clones templates authored in search.html rather than writing labels of its own. Both rules exist because a second copy of the site's prose is the copy that rots. These are instrument labels on a page that will never be published, and deleting the one include line removes every one of them. The alternative — authored templates in every draft — is a block of markup pasted into each one, which is the friction this exists to spare.

check-metadata.mjs check 10 keys on sitemap.xml, because that is this site's manifest of published addresses. A draft is not in it, so a draft branch stays green; the moment a page is accessioned the gate demands the block be gone. It fails on the noindex half too — a page the manifest advertises and the markup hides is two statements that cannot both be true. Made to fail in both shapes on a real published page before being believed, exit 1 with the fault and exit 0 reverted.

The gate's first version was defeated by this repository writing about it. Check 10 grepped for the bare string drafts/review.js, and the full sweep failed on /changelog and /what-is-settled — two pages that had just been given a register entry and a decision entry describing the feature. A gate matching a string matches the documentation of that string, which on a site that documents its own build is not an edge case. It requires an unescaped script tag now: prose naming the file writes &lt;script or wraps it in a code span, so the tag is the exact discriminator. Check 7 in the same file already knew this — it exempts a href because a link the reader chooses is not a request the page made, and its own comment calls that distinction "the whole difference between a usable gate and a useless one". Same lesson, second gate, found only because the sweep was run over every page rather than the ones that changed.

No gate measures the review furniture, so it was measured by hand — and the first two measurements found real faults. check-contrast.mjs sweeps root pages and this is built at runtime on a page it never sees. Every pair sits on --qe-card: ink 15.26:1 in daylight and 13.39:1 in the cabinet, moss 8.35:1 and 7.53:1, rust 7.52:1 and 7.57:1. --qe-paper-deep was the obvious ground and is wrong — moss and rust measure 6.90:1 and 6.21:1 on it in daylight, reproducing to two decimals the numbers that withdrew the recessed panel once already. And the 44px floor missed every Note button, because .qe-review-ui button does not match a button that is the review element rather than contains one; they shipped at 40.3px until they were measured. All 54 controls clear 44×44 at 375px now, none overlap, and scrollWidth equals the viewport.

Two smaller things, each paid for by watching it go wrong. A dl is one target, like a blockquote — the specimen block fragmented into twelve note buttons first, which is the quotation-cropping fault from the other direction. And a note whose paragraph is rewritten under it re-attaches by position and is marked the text here has changed since this note was written, rather than vanishing; silently losing a reviewer's note is the worse failure, and it still exports.

There is no draft template, on purpose. A skeleton page would be a second copy of the markup every sheet already carries, and it would rot. Copy the nearest sheet.

Both open questions were closed the same day, by the curl this entry asked for, and one answer was the bad one. The .netlify.app rule in _redirects does not reach a branch host — no location:, as expected. But Netlify does not send X-Robots-Tag on a branch deploy at all: drafts--queering-earth.netlify.app/on-being-ill answered 200, bare. Deploy Previews get the header; branch deploys do not. The draft page itself was covered, because noindex, nofollow is one of the three lines in its own block — but a branch deploy carries a full copy of all 27 published pages, and those had only rel=canonical holding them. That is real mitigation and it is the standard cross-host mechanism, but it is exactly what this site already judged insufficient one layer up, where _redirects 301s the .netlify.app apex rather than leaning on canonicals.

The fix and a correction to this entry's own design, which are one thing. _headers on the drafts branch carries X-Robots-Tag: noindex on /*, and that line must never reach main — if it does, every page on the site drops out of every index. It is safe only because promotion takes the file and never merges the branch: git checkout drafts -- on-being-ill.html from main, then the accession checklist.

Promotion is a merge was written into this entry and into CLAUDE.md before the branch had more than one thing on it, and it was wrong on its own terms: a long-lived branch holding three drafts cannot be merged to publish one of them — it publishes all three. Cherry-picking the single file is what the workflow required anyway, so the header costs nothing it was not already going to cost. The two halves are one decision and weakening either breaks the other.

Rejected: Deploy Previews instead of a branch deploy. Netlify does noindex those, and Helen would never see GitHub — Ryan would open the PR and send her the URL. But the URL changes per pull request, so she loses the stable bookmark that was the whole point, and a PR would have to exist for every draft. Not worth it for a header that one line supplies.

Nothing gates the header. The live probe is curl -sI https://queering.earth/ | grep -i x-robots, and an offline gate cannot tell which branch it is reading without asking git, which was judged not worth the fragility for a rule whose failure is this loud.

tools/check.mjs, and a gate that spent five days measuring in a browser it did not launch (2026-09-12) Link to this section

Ryan, after the lilac coda shipped: "It took over 20 minutes to test and deploy this simple change. The width gate is especially slow, and it looks like it ran three times." All three observations were right, and timing them turned up a second fault nobody was looking for.

Where the time went, measured rather than felt. The four generators are 4.8s and the six offline gates 5.6s together. check-overlap is 40s, check-contrast 53s, and check-width is 4:22 — three quarters of the whole bill, because it renders 27 pages × 10 typefaces × 4 widths × 2 papers. Nothing that is not Chrome costs ten seconds.

Settled: tools/check.mjs regenerates, then runs every gate, scoped to what moved. Three fixes, none of which needed new capability:

The scope is computed AFTER the generators run, and that is why this is a tool rather than a shell alias. make-records and make-whats-new write into pages nobody touched — the coda moved index.html by hand and what-is-settled.html and search.html by generation — so asking git first would scope to the edit and miss the pages the edit caused. Untracked files count too: a new page is the case most in need of measuring and a plain git diff cannot see one.

Which assets break scoping is DECLARED in the tool, in the two-list shape check-cache.mjs already uses. Nothing in a file's bytes says whether it can move a page it is not named in, so the inference is available, plausible and wrong. The stylesheet, the script, the fonts, font-files.json, reveal.mjs and the gates themselves force a full sweep; queering-search.js adds /search and nothing else; everything else is page-local by declaration. A new shared asset needs a line in one of the two lists. --all is always available and always correct.

Open: whether check-width itself should be made faster. Two candidates, neither built — render pages across three or four concurrent tabs in one browser, or sweep the nine extra faces only on pages that changed while the default face walks everything. Scoping made it moot for the edit loop; a full sweep is still four and a half minutes.

A gate must own the browser it measures in (2026-09-12) Link to this section

Found by timing the gates, not by any check, and no check here could have found it. Every gate reports on the site; nothing reports on the instruments.

Each Chrome gate spawned Chrome and then polled /json/version until something answered. On 7 September an orphaned headless Chrome from a neighbouring project's probe script took port 9414 and never let go. Every check-width.mjs run from that day to 12 September bound nothing, attached to that five-day-old browser, measured 27 pages in Chrome 152.0.7977.77 while .84 was installed, killed its own portless process on the way out, and reported PASS with no sign whatsoever. Five such orphans were up, one per interrupted probe, holding about 400MB, with 303 temp profiles behind them.

Settled: cdp.mjs owns the spawn, which reverses that file's own stated position. Its header argued the duplicated spawn boilerplate was fine because it "carries no footgun." That clause was false, and false in production. launchChrome() refuses two ways a sweep can happen in something we did not start:

It also removes the temp profile, which no copy did — awaited, because kill() only sends a signal: the first version removed it on the next line and left 25 directories behind in a single evening, since Chrome was still flushing and macOS lets a running process recreate a file you just unlinked. Made to fail in three shapes before being believed: a decoy holding the port refuses and exits 1, a browser that cannot start reports Nothing was measured, and the port free again passes.

The orphans came from ad-hoc probe scripts, not from the gates — the gates do clean up on their normal exit, confirmed after. So the transferable rule is about the probes: a script written to measure something once must still clean up after itself, because the bill arrives somewhere else entirely, days later, as a gate that cannot fail.

Clearing them did not speed anything up — 4:22 against 4:30, which is noise. That is a correctness finding, not a performance one, and the two were kept apart deliberately.

The lilac coda goes last, and being last had been its heading (2026-09-12) Link to this section

Eliot's four lines, the lilac bush and the click-to-load recording were mounted above the footer and last on the page on 9 September, and they were the last thing on it for two and a half hours. The cabinet's list came out of the footer that evening, the aims followed, and the drawers reorganised both on 11 September. Every one of those edits appended, which is the ordinary thing to do; the sum of them left a coda in the middle of the page, reading as a digression between the plate and the furniture. A coda stops being a coda the moment anything is appended beneath it.

Settled: it sits after both furniture lists, at the foot of main — last for a structural reason now rather than a chronological accident, since nothing on the home page follows the drawers. Ryan's call, 12 September 2026.

It also needed a heading, which it had never had, and the reason it had never needed one is the useful part. A passage at the end of a page, after the argument has finished, announces its genre by position. Moved into an outline — the rail derives from the page's own h2s — it has to be named in that outline, so it is Coda: the lilacs. The word does the job the position used to do.

The address is #lilacs, not a slug of the heading. Ids here are topical and authored precisely so a reworded heading does not take every shared link with it, and Coda is a word somebody might argue about later. The lilacs are not. Nothing else was needed: the rail picks the section up on its own, and the home page has no contents list to keep in step, its plate being the index it already has.

Tag balance is check 9 in check-markup.mjs, and turning it on found two more faults (2026-09-11, closes the open item raised the same day) Link to this section

Raised as open that afternoon and settled by Ryan within the hour: add the section balance check to check-markup. The open entry is kept below for the reasoning that led here.

It checks every element, not section, and that was measured rather than argued. Before writing a line, every non-void element on every page was counted open-against-close: the whole repo balanced except two — the section already known about, and an unclosed <strong> on /two-cohabitating-modes that had been bolding the rest of a list item since the sheet was mounted. So a declared list of containers would have bought nothing and been a second thing to keep in step. The house closes every tag, and that is now a rule rather than a habit — stricter than HTML, which permits implicit closes for p, li, dd and td, and justified because the three regex generators in tools/ need balance.

A STACK, NOT A COUNTER, AND THAT DISTINCTION PAID FOR ITSELF IMMEDIATELY. Counting opens against closes returns zero for <div><section></div></section>, which is mis-nested and breaks those generators in exactly the same way. The stack also names the element and the line where a counter can only say some total is off by one. On its first run it reported 16 problems on /ledger and /what-is-settled — both generated pages, both numerically balanced, and invisible to the counting sweep done an hour earlier.

The cause was make-records.mjs's inline Markdown converter, shipping overlapping tags. **Robert Earl Hardy, *A Deeper Blue*** came out as <strong>Robert Earl Hardy, <em>A Deeper Blue</strong></em>: the bold regex is non-greedy, so it took the first two of the three closing asterisks and left the third for the italic pass, which then closed the pair in the wrong order. Eight passages were built that way, in the two pages a reader goes to in order to check us.

The old comment was right that emphasis nests here and wrong that two ordered passes can read it. **A *b* C** happens to work; **A, *b*** cannot, because the closing run is ambiguous to a regex and is not ambiguous to a stack. Replaced with a delimiter resolver using CommonMark's flanking rule reduced to the one case this corpus has — a run may close only if the character before it is not a space, and open only if the character after it is not. That is what tells *A **B*** (italic holding bold) from **A, *B*** (bold holding italic), and both shapes appear in these files, so neither could be assumed. It still throws rather than emitting a stray asterisk, and now also throws on a run left open.

The fix changed seven lines across the two pages and nothing else, checked by diff, and make-records.mjs's own word-for-word round-trip proof passed unchanged.

Proved failing before being believed, in three shapes, each reverted after: the original missing </section>, reported against the </main> the browser would close it at; the unclosed <strong>, reported against its </li>; and a deliberately mis-nested </strong></em> … <em> that balances numerically, which is the case a counter cannot see. Clean tree exits 0; each fault exits 1.

22,709 elements balanced across 27 pages, and the count prints on every run — the same reasoning as the contrast gate's element counts, because a gate that checked nothing looks exactly like a gate that passed.

Nothing balances tags, and an unclosed section cost the feed an accession for a day (2026-09-11, closed the same day) Link to this section

Found on 2026-09-11 by counting the new arrivals feed's items against the register page: 58 accessions on the page, 57 in the feed. The Bewick accession of 10 September was missing its closing section and the two divs inside it, so every accession below it nested one level deeper and the file ended one tag short.

Nothing looked wrong, and that is the whole of the problem. A browser closes the tags itself, so /changelog rendered correctly the entire time. check-markup.mjs passed it — it reads parser-rewriting markup, duplicate ids and the single landmark, and does not balance containers. What it cost was silent: make-markdown.mjs matches an accession from its opening tag to the first </section> it finds, so the unclosed one swallowed the next accession whole, and the entry about every poem arriving in the Markdown mirror as prose had never been in the feed at all.

Fixed. The question left open is whether a gate should exist for it. Arguments both ways, and the house bar is that a check which cannot fail is a check nobody reads:

The second answer was the one taken, within the hour, on Ryan's call — see the entry above for what it found. Star Stuff's check-classes remains the standing next port.

/whats-new is the cabinet by date, and the one feed became two (2026-09-11) Link to this section

Ryan asked for the pair Star Stuff has kept from the start — a What's New page and an RSS feed. Half of it already existed and could not be reached; the other half turned out to be two things.

The feed was already there and nothing linked to it. /feed.xml has shipped since the agent-readiness pass, advertised in every page's head as rel=alternate and on every response as a Link header — so a client handed the URL could find it and a person could not. There was no visible, pressable link to it anywhere on the site. That is the actual gap Star Stuff's page fills: whats-new.html and feed.xml there are one list in two formats, for people and for machines.

One feed became two, on Ryan's call, mid-build. The old feed carried this register's accessions — new sheets, corrections and housekeeping in one stream. Split: /feed.xml is the pages as they arrive, and /register.xml is the register. They are two lists for two readers — somebody following the work wants to know a sheet was mounted, somebody auditing us wants to know a label was corrected — and merging them made the second invisible inside the first, on the site that least wants its corrections buried. The pages took the old name, so anyone already subscribed stays subscribed to a working feed and simply begins receiving pages, which is the list most people mean by feed; the register's is named for what the site already calls that page.

The page and its feed come out of ONE tool and one pass, so they cannot be made to disagree about what arrived or when. make-markdown.mjs keeps the register feed, because it already parses the register.

The listing is written between markers, which is a deliberate departure from the port. Star Stuff generates the whole of its page from a template inside the tool, and its own notes record the cost: a site-wide pass added a skip link to all 197 pages, the next build rebuilt that one from the template, and the skip link was gone with the tool reporting a clean build. A generated page does not conflict, it reverts. So this follows make-records.mjs instead — authored page, generated listing — and a sweep that touches every page keeps its edit here.

THE REGISTER CANNOT DATE A PAGE, AND THAT WAS MEASURED RATHER THAN ASSUMED. The obvious source was this site's own register, and it does not work: Mounted means anything added to a page, not a page coming into being. /design carries five such entries, /two-cohabitating-modes six, the home page ten — and /privacy carries none at all, because nothing was ever mounted on it. Earliest-Mounted-wins would have dated several pages by accident and one not at all.

So the date is git log --diff-filter=A on the current path — a measurement of the repository, with the same standing as check-width.mjs measuring a rendered box, and not a second hand-kept copy of an authored fact. And it is gated against the authored fact wherever one exists: eleven sheets carry an accession stamp with a datetime and twelve pages carry a provenance line with another, the generator compares all three for every page, and it throws on a disagreement. All twelve agree today — checked before a line of the tool was written. Neither source alone could do this: the stamp cannot date /privacy, and git cannot know what we meant.

The bootstrap is self-healing rather than an override table. A page being written has no commit that added it, so an uncommitted page is dated today, loudly, and the next run after the commit takes git's answer — a hand-kept date table would have had to be right forever; this has to be right once, and says on every run when it is guessing.

Three things were found by running it rather than by reading it, which is this house's own rule about new gates arriving three times in one build:

The listing is stripped from the search index as chrome, the .qe-plate-grid treatment at twenty-six: a searcher who types a sheet's subject wants the sheet, not the index that names it, and this one page carries a line about every page on the site. Nothing is lost — each summary is that page's own meta description, which /llms.txt already publishes. The page's own prose stays indexed, at four records.

The footer row went from 14 links to 15 and was remeasured, because nothing in tools/ measures a hit area: 6 lines at 320, 5 at 375, 2 at 768 and 1280; no overlaps at any width; every target at least 64.7 × 55.7px; scrollWidth equal to the viewport throughout.

Sporting Grotesque is set smaller, and the width gate now sweeps all nine faces (2026-09-11) Link to this section

Raised as open the same afternoon and settled by Ryan within the hour: option 1, and teach the gate the nine faces.

The fault. With Sporting Grotesque picked in the reading settings, the home page's document measured 361px at a 320px viewport, 388 at 375, 427 at 414 and 770 at 768, fitting only from about 1024 up. Horizontal body scroll, reached through a setting the site offers, failing the 320px reflow WCAG 1.4.10 names and the panel's own rule that every setting must be additive. Pre-existing at d3ce2c7. It is the only one of the nine that does not fit: Sporting's display cut is far wider than the other eight at the same size.

The size is a measurement, and the expected answer was wrong. The obvious target was clear the 20px gutter, and it is not the bar, because the default face does not clear it either — at 320px Fraunces leaves 12.1px, since the masthead has always been allowed to encroach there. So the real bar is no tighter than the house's own tightest. Measured at 320: 8.4vw leaves 5.4px, tighter than the default; 8vw leaves 13.2px, which is not; 7.6vw leaves 20.9px and clears the full gutter at the cost of a visibly smaller title. clamp(1.9rem, 8vw, 5rem) is the middle one. Checked from above as well — 8.8vw still scrolls at 320 by 2px and 8.6vw fits by 2px, a margin too thin to survive another browser's rounding. Nothing changes at 1280, and the other eight faces and the default are untouched.

It is a metric fact about the face, not a preference, and it has the same standing as sets_body in the font manifest — which exists for exactly this reason: Victorianna ships Thin alone, four faces have no italic, and now one is too wide for the masthead at phone sizes.

The gate hole was the more important half. check-width.mjs had rendered one of ten states on twenty-five pages and reported PASS throughout — the contrast gate's "8% of itself" blindness, in a second gate, three days after that lesson was written down. It sweeps every face now.

Proved by making it fail, per the house rule: withdrawing the Sporting size reports five failing passes on index.html, names the typeface in each, points at <h1.qe-wordmark> and the word Earth, and exits 1; restored, it passes 25 pages × 10 faces × 6 passes.

text-align: center does not centre a line wider than its box, and the masthead had been 34px off for its whole life (2026-09-11) Link to this section

Ryan, with a screenshot of the home page under a wide typeface: the wider fonts available in the font selector don't center the title. They do not, and neither does the default one.

The mechanism is a sign change. text-align distributes leftover space along the line. When the line is wider than its box the leftover is negative, there is nothing to distribute, and the line is laid from the start edge with the whole overflow running off the end. Measured at 1280: main is honestly centred at 368…912, the masthead's content box is 416…864 — 448px — and the wordmark's ink is 515.9px. It began exactly at 416, ended at 931.9, and sat 34px right of the page's centre line.

It is not a typeface bug, though a typeface is how it was seen. The offset is 34px with the default face, 28.4 with Victorianna, 68.8 with Coxinelle and 162.4 with Sporting Grotesque — the wider the face a reader picks, the further right the wordmark leans. Nine faces made visible a fault that had been shipping with one. Confirmed pre-existing at d3ce2c7, before anything in this session, with identical numbers.

Below about 1024px it looks right, which is why it survived. There the wordmark fits its box, the leftover is positive, and text-align centres correctly. Every width this house routinely measures at — 320, 375, the control-tray checks — is in that range.

width: max-content plus left: 50% and a negative translate. The box becomes as wide as the letters and is centred on the container's centre line whether it fits or not: the one centring idiom whose arithmetic does not change sign. Verified at 0.0px offset for all nine faces at 375, 768, 1280 and 1920, and in plain view, the cabinet, and on both papers.

translate rather than transform, deliberately. Plain view switches transform off component by component — the lean, the wobble, the drift — because each of those is a decoration. A centring correction is not one, and using the independent property means a future transform: none written for the wonk cannot silently push the masthead back off centre.

Flex centring on the masthead measures identically — same geometry to the tenth of a pixel, no margin-collapse difference — and was passed over only because it restyles every masthead child to fix one of them.

A break opportunity at the dot was tried and is refused. content: "\200B" on .qe-dot::after would let Queering. / Earth wrap instead of overflow, which sounds like the typographically natural answer. Measured, it wraps the default face onto two lines at 1280 as well as at 320, because the wordmark exceeds the 448px box at every desktop width — so the cure for one face's overflow would restyle the masthead for all nine. The max-content box forecloses wrapping entirely, which is also a guard: after overflow-wrap broke Queering.Ear / th earlier the same day, a wordmark that cannot wrap by construction is worth having.

Centring fixed three of five overflow conditions on its own, because a symmetric overflow is half as deep on each side: Coxinelle at 320 (325px document) and Insolente at 320 (322px) now fit. Sporting Grotesque still does not, and that is open — see below.

Monotropism, never monotropy — they are different people's words (2026-09-11) Link to this section

Ryan, on the masthead section of /two-cohabitating-modes: the word "Monotropy" is associated with Bowlby's attachment theory, which we do not endorse. Let's avoid using monotropy.

Two words one syllable apart, from two unrelated literatures.

So the near-homonym does real damage in one letter. Writing monotropy for a theory of attention hands the reader a framework about mothers, ranked caregivers and innate deficiency — on a page whose whole argument is that two modes are equal and neither is a grade. It would import the exact thing the page is written against.

The rule: this site writes monotropism and polytropism, and never monotropy or polytropy. The words are not interchangeable and the shorter one is not a shorter form of the longer.

Sheet No. 8 had it right and the new sheet did not, which is the useful detail: /monotropa-uniflora uses monotropism thirteen times and monotropy never, because it was written with the 2005 paper open. /two-cohabitating-modes got the term right in its prose and wrong in the heading above it, the id under that heading, two drawing comments, the stylesheet and two of the cabinet's own records — a correct body under an incorrect label, which is this site's characteristic failure appearing in its own house rather than in a source.

#monotropy became #monotropism, and that is a published address changed. The sheet was one day old and the only things pointing at it were the finding aid's generated manifest and its own contents list, both derived. Worth noting rather than doing silently: an authored id is meant to be permanent, and the reason to break one has to be better than tidiness. Carrying a repudiated term in a URL is better than tidiness.


A ninth gate, because three pages scrolled sideways past eight of them (2026-09-11) Link to this section

Ryan found it by hand on /changelog: a 414px document at a 375px viewport, pushed out by one inline code span holding performance.getEntriesByType('resource'). He asked whether the failure being invisible to every existing gate justified a small guard, and asked for the reasoning either way. It does, and the argument is not that the fault was bad — it is that the fault recurs by construction.

Three pages, not one, and the sweep is the part that changed the answer. /changelog measured 414px at 320 and 375. /ledger measured 812px at 320 and 375, and 943 at 768. /what-is-settled measured 425. All three had been live since the day each was mounted. A single overlong span on one page is an edit; three pages and six failing conditions is a class.

The strings are what a ledger is made of. DOIs, archive.org identifiers, sha256 masters, SKS file paths, a deploy hook URL — none has a space or a hyphen in it, so a line box cannot end anywhere inside one. ATTRIBUTIONS.md grows one of these every time the credit-source skill records a source; DECISIONS.md grows one every time a session settles something; make-records.mjs pours both onto a page between markers. The hazard is attached to a routine workflow, so the guard has to be too. That is the same standing-hazard argument that justified check-cache.mjs, and it is stronger than "the failure happened once".

What no existing gate could see, and why check-overlap.mjs is the near miss. It is the only other tool here that knows where anything is, and it asks a different question: is this text on top of that text. Text running past the right margin is on top of nothing — there is nothing out there to collide with. Its clip walk does not catch it either, because the document is not a clipping container: it grows to fit. And its screen pass is 1280px, where none of the three faults exists.

Folding it into that gate was considered and refused, for two reasons. Widening the overlap sweep to 320 and 375 would surface a flood of narrow-width collisions nobody has ever triaged, and gating on those is a separate project that would have to start by deciding which are real. And a tool named for text landing on text should not quietly also be the one that measures margins — this house spends a lot of care on a name meaning one thing, and the overlap gate's own header argues its three fault kinds are one positional sweep. Document width is not that sweep; it is one number per pass.

320 is not an arbitrary floor. WCAG 1.4.10 asks that content reflow to 320 CSS px without two-dimensional scrolling, which is 1280px at the 400% zoom the same criterion names. 375 is the phone this house already measures controls at. 768 and 1280 are in the list because /ledger failed at 768 — a fault that exists only on a phone is a guess, and this one was not.

It has no --check flag, deliberately. Two gates here shipped as a report that printed its findings and exited 0, and the contrast gate stayed advice for as long as CLAUDE.md forgot to pass the flag. A gate whose default is to pass has not shipped. This one fails when it finds something, always.

It measures paper, and paper is where text was actually being lost. On screen an over-wide string is a nuisance the reader can swipe past. On paper there is no swiping, and @media print deliberately sets .qe-editions-scroll { overflow-x: visible } — so /ledger was putting 802px of content onto a 717px A4 sheet with both master sha256 hashes running off the edge of the provenance table. Text off the sheet, in the file whose entire job is recording provenance, on a site whose predecessor shipped 44 of 46 pages printing blank.

It found a second fault on its first honest run, which is the best evidence for it. The home page's .qe-vined frame bleeds out by its own padding so the cards keep the full measure — correct on screen, where main carries a gutter to absorb it. In print main is max-width: none; padding: 0 and there is nothing left to absorb anything: 775px of home page on a 739px Letter sheet, hanging off both edges. The print block had already overridden the padding and left the margin alone. One half of a pair reset, and no eye was going to catch it — the cards stayed inside the sheet, so only the rule and the corner sprigs were being trimmed, and a frame cut flush with the paper looks deliberate.

Made to fail before being believed, per the house rule, and both halves separately. Withdrawing the wrap rule reports nine failing passes across the three pages; withdrawing the print margin reports two on the home page; the restored stylesheet reports PASS across 25 pages, four screen widths and two papers. Its first draft named the wrong words — it reported the overflowing run ending furthest right, which for an unbreakable string is the innocent tail after it, so on /changelog it pointed at ", not out of a reading of the source." rather than at the code span before it. It reports the widest overflowing run now. A gate that names the wrong words is a gate somebody edits the wrong words to satisfy.

A wrapping rule is checked by counting line boxes, not by measuring the document (2026-09-11) Link to this section

Written because the first version of the fix below shipped, deployed, and broke the masthead. body { overflow-wrap: anywhere } cleared all three overflowing pages, passed all nine gates including the new one, and Ryan opened the home page to find the wordmark reading Queering.Ear / th.

The rule was right and the scope was wrong, and the reason the check missed it is the part worth keeping. anywhere does two things: it permits a break inside a word, and it shrinks the element's intrinsic min-content. The second is what recovers the sha256 column on paper — and it is also what lets a display word break where it previously sat wider than its box without anybody minding. Sitting wider than its own box is not the same fault as scrolling the document, and the masthead had been doing the first quite deliberately: main is capped at 34rem and the wordmark is bigger than that, overflowing symmetrically into gutters that are there to receive it.

So every measurement I took was of the wrong quantity. A 25-page sweep of document.scrollWidth at four widths and two papers, before and after, reported no change anywhere but the three faulting pages — because none of the damage moved a document width. The wordmark broke inside the measure. The reading panel's Typeface label broke inside a fixed-width row, on all twenty-five pages. Every table on the site re-laid out its columns. All of it invisible to the only number being watched.

The check that finds it is a line-box diff: for every text node on every page, count Range.getClientRects().length with the rule and without it, and report every element whose count moved. It is four lines of difference from the sweep that missed everything, and it found 324 changed elements in one run. tools/ has no gate for this and probably should not — a line count changing is usually the point of a typographic edit, so it cannot be a pass/fail. It is a diff to read, by hand, whenever a rule touches wrapping, and that is now written beside the rule.

Narrowing it took three attempts, and the two rejected ones are the useful record. code, a fixes /changelog and /what-is-settled but leaves /ledger at 402px, because that page carries bare <https://doi.org/…> in running prose as a plain text node with no element around it — hence .qe-record p, li, which exist only because there is nothing else to hang it on. Then a turned out to reach a.card, and the Register card's kind chip broke across two lines at 1280px. A structural selector was tried and does not help: a card lives inside an li, so :is(p, li, …) a catches it too. A selector list that looks careful while catching the same element is worse than an exception that says what it is protecting, so a.card is excluded by name. .qe-editions td/th was tried and is not in the rule — a code element's own anywhere already shrinks what the column sizing reads, so the paper fix needs nothing else.

And the technique was already here. .qe-references p a { overflow-wrap: anywhere } had been in the stylesheet since the references block shipped — this house had reached for anywhere the first time a bare URL would not fit and scoped it to the one component somebody was looking at. That is the precedent, not a casualty; the general rule is that rule generalised, and the scoped copy has been folded into it.

overflow-wrap: anywhere, not break-word, and the difference is only visible on paper (2026-09-11) Link to this section

The fix for the above, and the choice between the two is a measurement rather than a reading of the specification.

Fixed in queering.css and not in the register's prose, on Ryan's instruction and for the reason the register exists: it is a dated record, and rewording an entry to make a layout fit would falsify it.

The house pattern for wide content — scroll it inside its own overflow-x: auto box — is for BLOCKS, and it is already spent where it belongs. .qe-record pre scrolls, with its reason written beside it: a wrapped command line is one somebody pastes wrong. .qe-editions-scroll scrolls because a comparison table is an object with columns. Neither answers an identifier set inside a sentence. An inline element has no scroll box at all; making a code span inline-block to give it one would put a scrollbar in the middle of a line and split the ruled tier this site uses to say what a panel is. So the inline form wraps and the block form scrolls, which is the same decision both times — show the whole string, by whatever means that medium has.

break-word and anywhere are indistinguishable in flowing prose and both clear all three pages on screen. They part company inside .qe-editions, because only anywhere shrinks intrinsic min-content: under break-word the sha256 column stays as wide as the hash, since the table's track sizing never learns the string can break. On screen the table's own scroller hides that completely. On paper it does not, for the reason above — and paper is where the hashes were being lost. Measured both ways before choosing; the specification says this and the measurement is what made it matter here.

It fires only when a word would otherwise overflow its line — but which words those are depends entirely on where the rule is allowed to reach, and inherited from body it reached the masthead, a form label and every table on the site. See the entry above: the scope was corrected the same day, and the measurement that certified the wrong version is the thing to remember.

The readings drawer had three names and now has one: The plate (2026-09-11) Link to this section

Raised after the drawers shipped, settled by Ryan the same day. Every other drawer's name appears in five places and is the same word in all five — the group heading in tools/pages.mjs, the section heading on the home page, /llms.txt, the finding aid's manifest, and the collection page's own h1. The readings drawer had three: The readings in pages.mjs, What grows here on the home page, and The plate on the page itself.

Two of the three predated the collection pages, which is the part worth keeping. The readings and What grows here had disagreed since the finding aid shipped, and nobody noticed because nothing put them side by side. Giving the set a page put all three in one sentence and the drift became visible in an afternoon. A set acquires its second name long before anybody chooses one.

The plate wins, and the evidence is that the site had already chosen it in prose.

What it costs: What grows here is gone as a visible heading, and it was a good one — botanical, a question rather than a label, older than almost everything around it. That is the price of one name, and it is the right price: the alternative is three names, one of them false.

/#what-grows-here DID NOT MOVE. The id rule — authored topical anchors, never slugs of headings — exists exactly for this, and this is the first time it has been cashed in: the heading was reworded and all seven anchors pointing at it still resolve — three in the register, one on /mission, one on /the-plate, one in the finding aid's manifest, and the section's own .qe-anchor — along with five further mentions in prose and code spans. Tidying the id to match the new heading would break precisely what the rule protects. The address quietly keeps the old name, which is the most honest place for it.

The register's own older entries were not rewritten. Four of them italicise What grows here; they are dated records of what the page said when they were written, and editing them to use a name that did not exist yet would falsify the register in the one file whose job is to record that kind of failure.

The three collection-page kickers became one word, Drawer. Drawer · the readings carried the dead name, and Drawer · the plate would have said the h1 twice — which the other two had been doing since they shipped.

Three drawers, and "Drawers" is a word this file already refused once (2026-09-11) Link to this section

Ryan: "I like breadcrumbs and collection pages." The two lists at the foot of the home page — The founding papers and The cabinet itself — were already collections in everything but address, and the plate was a third. Each now has a page: /the-plate, /the-founding-papers, /the-cabinet-itself.

THIS IS NOT THE COLLECTION DECISION THIS FILE DEFERRED, AND THE DISTINCTION IS THE POINT. The entry above — no collections yet, and the trigger is named — defers runs: three sheets sharing a lens, named retroactively the way Helen names hers, because a run declared at n=1 is a promise with nothing written to keep it. That trigger is untouched and the collection-*.html namespace is deliberately left empty for it, which is also why check-markup.mjs's ported badge check stays stood down and armed. What shipped today is structural, not thematic: three drawers that already existed, one of which is the whole plate, and nothing is sorted into anything.

"SIX DRAWERS" WAS REFUSED AND THESE THREE ARE NOT IT. The rejected proposal was art · literature · poetry · politics · people · history as a browsable taxonomy, refused twice over — five visible promises we were not keeping, and a forced single filing on a piece like On Being Ill, which wants Literature and People and Politics at once. No sheet is sorted here. Two drawers hold the pages that are not readings; the third holds every reading there is. Nothing is filed anywhere it is not already filed.

Ryan named the menu, choosing Drawers over Collections and Cases with the collision stated in advance: the tray's ground control says Cabinet, and a Drawers menu beside it could read as a second view control. Accepted because the home page's own prose already says how to look through the drawers, and because a disclosure with a triangle and a list of links is not a pressed-state button.

The plate got a page, on Ryan's call, and it earns it by not repeating the front. The alternative was pointing the breadcrumb and the menu at /#what-grows-here, which is a real address for a real index. What decided it: the three sheet kinds are settled in this file and stated nowhere a reader meets them. A reading has an order and arrives somewhere, an essay is ours, a wall has a chorus — that is real content with no home, and it is now on /the-plate along with what the accession number does not say.

THE GLOSSES LIVE ONCE AND THE COLLECTION PAGES DO NOT REPEAT THEM. Nine pages are described in one sentence each in .qe-furniture on the home page. Copying those onto a collection page is nine sentences free to drift, in a cabinet whose loudest rule is that two copies of the same words drift and the copy nobody is looking at is the one that rots. So:

A collection page's line in one of the two home-page lists is the pointer at the head of the section it collects, not a <dt> inside it. Otherwise The cabinet itself would appear in its own list and the recursion would have to be explained to a reader. Each of the three sections now ends its intro with About this drawer.

No sibling nav on a collection page. The drawers menu lists the other two drawers at the top of every page with the current one marked, so a .qe-elsewhere carding the same three is the two-competing-navigational-lists fault this repo already refuses on the home page. For /the-plate it would be worse: the page already cards every sheet there is.

Each group's collection page is the first entry in its own group in tools/pages.mjs, so /llms.txt, the finding aid's manifest and the reader's index stay one derivation. index is in no collection: the home page is above the scheme rather than inside it.

The breadcrumb stops at the drawer, and it was already here one crumb long (2026-09-11) Link to this section

.qe-home was a lone link home on twelve pages; seven more carried the group name beside it inside .qe-kicker as plain text — Queering Earth · The founding papers, with the second half leading nowhere. The collection pages made that text an address, and the two shapes became one .qe-crumbs nav on nineteen pages.

It never names the page it is on. The h1 is the next thing in the masthead, so a third crumb is the title printed twice a line apart. The JSON-LD breadcrumb carries all three items, because a machine's copy has no heading under it — and it goes inside the page's one existing block as a breadcrumb property, because check-metadata.mjs requires exactly one JSON-LD block per page and is right to.

The separator is drawn in CSS. It must not join the accessible name, must not reach the Markdown, and must not be something a reader can select into a quotation. It takes --qe-moss rather than a decorative token, because it is a glyph and nothing here measures a ::before.

It sits inside <main>, which the nav rule otherwise forbids, for the reason .qe-contents does: that rule stops one sheet's navigation being indexed as another sheet's content, and a trail naming this page's own position cannot do that. It lives in .qe-masthead, which make-search-index.mjs already skips — so it reaches the .md, where an agent wants to know where a page sits, and not the finding aid, where it would be nineteen identical results.

Targets measured after, because nothing here measures a hit area: 45px tall, 107px and 67px wide, 18px apart, at 375px and at 1280px. A third crumb would need measuring again.

/404 keeps the old shape and gets no breadcrumb, for the reason Star Stuff gives its error page no collection badge: a trail would claim the address the reader asked for belongs to a drawer, when the whole message is that it does not exist. index gets none either.

A panel hung off its own control moves when a control is added (2026-09-11) Link to this section

The reading panel had been right: 0 on its own summary since it shipped, which made its position a function of how many controls sit to its right. At 1280px it cleared the measure by 31px. Adding the drawers control moved the control 81px left, took the panel with it, and landed 50px of it on the lede on eight pages.

check-overlap.mjs reported it and nothing else would have. No amount of care about the new control would have predicted it, because the thing that moved was the old one. The tray's own note already said a new control is a measurement rather than a markup edit; it was right about the row and silent about the overlay.

Both panels now hang off .qe-controls, whose right edge is the gutter at every width, so a seventh control cannot move either. The cost is paid explicitly: .qe-controls > *::after grows a 44px hit box that only works because each child is positioned, so for these two the box moves onto the summary and the tray's rule is switched off for them rather than left to misfire against the tray. Measured at 320, 375, 768 and 1280px: every hit area 44×44 or better, none overlapping, scrollWidth equal to the viewport at all four, both panels inside the gutters at 320.

The refused alternative was hanging the drawers panel off its own control. Measured at 375px the tray wraps; a 19rem panel on a control whose right edge is at x=98 spans to x=−142, off the left edge, taking the document's scrollWidth with it — the horizontal body scroll the layout rule forbids outright.

Two tray disclosures share a name, and both gates had to be taught (2026-09-11) Link to this section

Two overlay panels in one tray can both be open with JavaScript off: a details toggles natively and the close-the-other convenience was script. They share name="qe-tray" now, which is HTML's exclusive accordion — opening one closes the other with no script at all. Verified by setting open directly, with no click and therefore no listener involved. The script's Escape and click-away handlers moved from the reading panel alone to a loop over both, which lost a copy rather than adding one.

That fix made the two rendering gates disagree, and the disagreement is real rather than an artefact.

Proved rather than assumed, per the rule about watching a new gate fail: the drawers panel's hints in a 2.15:1 colour report three failures under check-contrast.mjs and none once restored, so the panel is genuinely being measured. And a pristine <details> injected into a live page does not open under the browser-automation keyboard either, so keyboard activation of a summary is not verifiable through that tool — the trusted pointer click is, and it was.

Two attention shapes, and the width a masthead is actually reviewed at (2026-09-11) Link to this section

Ryan's call after the blown-up tray mark was refused twice: something else for the header. The page already carries a fox and a hedgehog twice over in Bewick's 1792 engravings, so the masthead carries the argument rather than the animals — one unbranched stem with a single five-petalled flower against a low stem branching into a broad head of many small florets. Monotropism against polytropism, and Monotropa uniflora means one turn, one flower, which is Sheet No. 8's whole subject. It sits in the register this site does not get wrong, and it cannot restage the predation problem, because plants do not eat each other.

THE INVARIANT IS EQUAL FLOWER AREA AND IT IS COMPUTED. The claim the drawing makes is different distribution, equal mass; two areas that were merely near would rank the two modes by accident, which is a gold join on an uncorrected sheet in the most prominent place on the sheet. The rosette is a five-lobed polar rose whose area is exact — πR²(a² + b²/2) = 826.24 — and the floret radius is solved back out of it: 29 × π × 3.011² = 826.24, residual 1.1e-13.

THE FINDING WORTH KEEPING IS THE REVIEW WIDTH, NOT THE DRAWING. Four passes were judged against a 544px review sheet, because 34rem is the measure and 34rem is 544px. A block inside main does not get 544px. It gets 448. That number is already in this file, recorded against .qe-wide — measured on screen, the provocation is 448px, the content box every other block gets — and it was not applied. So the drawing was tuned 21% larger than it renders: on the real page the rosette came out 26px and read as an asterisk, and the head read as a cup. Rescaled for 448 it is 41px and reads as a flower. Review a masthead at 448px. The measure is not the content box.

Three more were drawn and refused on the way, each by looking:

And three dead classes, caught by hand because the gate for them is not ported. The stems carried .stem-main, .stem-branch and .stem-twig alongside .stem, with no rules anywhere — the stroke hierarchy was inline all along, as /on-being-ill does it. They did not render black only because each element also had .stem. check-classes is still the next port from Star Stuff, and this is the second drawing to want it. Until it lands, the check is a dozen lines: collect every class in the drawing, and grep the stylesheet for each.


Seven of the eight gates cannot tell a fresh build from the last successful one (2026-09-11) Link to this section

Measured by deliberately breaking a source file, not recalled from the accident that prompted it &mdash; the house rule being to make a gate fail before believing it. An entry with a paragraph indented outside any list was inserted into DECISIONS.md, which make-records.mjs correctly refuses, and the eight gates were then run against output that had not been rebuilt:

check-markup.mjs --checkPASS
check-sitemap.mjs --checkPASS
check-metadata.mjsFAIL
check-card-order.mjs --checkPASS
check-addresses.mjsPASS
check-cache.mjsPASS
check-contrast.mjs --checkPASS
check-overlap.mjs --checkPASS

WHAT THIS DEMONSTRATES, EXACTLY: seven gates reading the files on disk cannot notice staleness, because a stale file is a perfectly valid file. They are measuring markup, colour, geometry and cache headers, and every one of those is a true statement about yesterday's build. Only one gate asks whether the files are current.

It does NOT demonstrate that the regenerate-into-memory design beats an mtime check, and the first version of this paragraph claimed it did and then conceded the opposite two sentences later. A generator that throws writes nothing, so the derived file stays older than the source that broke it and mtime catches this case too. The claim was self-refuting as written, in the entry about signals going unread, which is its own small joke.

Where regenerating into memory does earn its keep is a different case, and this repo runs into it constantly: git sets a written file's mtime to the moment it wrote it. After a checkout, a merge or a conflict resolution, every touched derived file is newer than every source &mdash; so mtime reports the whole tree fresh at precisely the moment three sessions have been rewriting it. The same goes for a source edited and reverted, and for two sources feeding one output where only one moved. CLAUDE.md's <q>exact rather than an mtime guess</q> is right, and this accident is not the evidence for it.

SO THE EVIDENCE WAS MADE, RATHER THAN LEFT AS A DEDUCTION. Edit DECISIONS.md and do not regenerate; then let git rewrite what-is-settled.md, as a checkout or a merge does. The two verdicts then disagree on the same pair of files:

mtimederived is newer than or equal to its source &mdash; fresh
content, via check-metadata.mjsstale, and it fails

The two timestamps came out identical to the second, which is also what a session reported from a worktree the harness had recycled underneath it: DECISIONS.md, what-is-settled.md, changelog.html and changelog.md all written at once, source and derived indistinguishable by time. A tree in that state reads entirely fresh to mtime whether or not the generators have ever been run against it &mdash; and a merge, a conflict resolution or a recycled worktree puts it in that state routinely, which is the condition this repo has been in for most of two days.

THE INTERLOCK EXISTS, IT FIRED, AND IT WAS IGNORED &mdash; which is the actual fault and is worth stating precisely, because the tempting conclusion is that a guard is missing. The documented command is make-records && make-search-index && make-markdown, and && is the guard: tested here, a throw in the first aborts the chain and steps two and three never run, so no stale intermediate is propagated into search-index.json or the .md files. What went wrong in the original accident is that the gate run came after that chain as an unconditional separate statement. The chain aborted, its final echo regenerated never printed, the signal was sitting in the output, and the gates ran anyway.

Two rules.


Counting idioms that answered a different question than the one asked, and none of them errored (2026-09-10) Link to this section

Measuring one number &mdash; how much verse the Markdown flattening fault had flattened &mdash; took three sessions and eight wrong answers, and the wrong answers are the entry. Not one of them was a bug in anything in this repo, and not one of them failed. Every single one returned a plausible figure.

The title carried the number "six" for one commit and no longer does. Two more arrived after it was written, which is precisely the fault this file records against the home page's <q>Four pages that are not specimens</q> sitting above a list of six: a count in prose beside a list is a second copy, and it is the copy that rots. Nothing can derive this one, so it was removed rather than incremented.

The settled number, in the end: 219 verse lines, 48 verse blocks, 171 hard breaks, across 10 pages. It reconciles exactly, because 219 - 48 = 171 &mdash; a block's last line takes no trailing break.

Four were tool defaults.

toolwhat was askedwhat it answered
grep here is ugrepis this markup No.&nbsp;1 or No. plus a literal spaceprinted the entity decoded, so both forms looked identical and a phantom difference got chased across nine sibling navs
grep -chow many occurrenceshow many lines containing one, so a page with eight verse lines on one physical line reported 1
zsh, unquoted expansionnode tools/check-markup.mjs --checkdid not word-split, so --check became part of the filename and node reported module-not-found &mdash; which reads as a gate failure. See the shell note below: this row is four instances, not one.
perl scalar(()=/.../g)how many matcheswith capture groups in the pattern, returns the captures, so every block counted twice

AND THE FACT UNDERNEATH THE ZSH ROW, WHICH IS THE ONLY PART OF THIS ENTRY THAT PREDICTS RATHER THAN RECORDS: the tool is called Bash and it runs zsh. One command settles it, which is what keeps this a fact and not folklore &mdash; echo $SHELL; echo ${ZSH_VERSION:-none}; echo ${BASH_VERSION:-none} returns /bin/zsh, 5.9, none.

So these were never three sessions happening to write zsh-flavoured mistakes. Every habit carried over from bash is a latent wrong answer here, and the ones that have already fired are the differences most likely to appear in a throwaway one-liner:

THE LAST ONE IS THE BEST INSTANCE IN THIS ENTRY, BECAUSE THREE THINGS HAD TO LINE UP AND ALL THREE ARE ORDINARY. It was used to check whether the verse fix had survived every commit since it landed &mdash; the one thing actually at risk. zsh mangled the path; 2>/dev/null, added to keep the loop's output clean, hid fatal: ambiguous argument; and an empty stream made grep -q fail, which printed as MISSING for all eleven commits, uniformly and confidently. A uniform answer reads as a real finding rather than a broken probe. The report it was one keystroke from producing was that the converter fix had been reverted from the entire branch &mdash; a false alarm about precisely the thing the session had been warned to protect. Suppressing stderr converts an error into an answer, and it is worth writing that down on its own.

Several of these were misfiled at the time, which is the entry's own thesis operating on the entry's own contents. The glob refusal was recorded as a grep quirk; the array subscript was read as a quoting problem and silently worked around in Python without being diagnosed; and the history modifier was read, for one command, as the probe string being wrong. None of them errored in a way that named its cause: one returned a plausible wrong explanation, one a plausible wrong culprit, and one a plausible wrong result &mdash; and they stood until somebody asked what the shell actually was.

Two were regexes against our own markup, and they are the ones to actually worry about, because the first four are general knowledge and these two are specific to this house:

WHAT FINALLY SETTLED IT HAD NO REGEX IN THE COUNTING. Walk the p and div open and close tags keeping a depth stack, attribute each verse-line span to the innermost element still open, and count distinct holders. The nesting stops being a special case by construction, because a wrapper that directly holds no line is never counted. That produced 48 first time, per page: two-cohabitating-modes 13, wild-nights 11, the-tempest 7, invention-of-normal 6, promises-like-pie-crust 3, five-unmistakable-marks 3, monotropa-uniflora 2, flower-codes 1, index 1, manifesto 1.

AND TWO MORE, AFTER THE ENTRY WAS WRITTEN. The first is the only one where the wrong answer was right about the bytes and wrong about what they mean, which is a harder class than the six above:

  1. Not noise, and fully explained: DECISIONS.md line 2516 is netlify api getSite --data '…' \ &mdash; a shell line continuation inside a fenced block &mdash; and it reaches what-is-settled.md through the generator, so the same one backslash was counted in two files. It genuinely is a line ending in a backslash. Every other idiom here returns a number that is wrong; this one returns a number that is right about the characters and wrong about the markup they sit in. Three sessions met it and got three outcomes. One saw those two files in a grep -c '\\$' *.md listing and set them aside as pre-existing without asking why. One asked why, and traced it. And one checked whether its own entry had introduced a false hard break, found the backslash-terminated line, followed it into the fenced block and stopped &mdash; catching at the last step a defect it had been about to report, and which it had invented. Same trap, three distances from publishing it.

THE AUTHORSHIP OF THIS ENTRY, WHICH TWO SESSIONS GOT WRONG IN OPPOSITE DIRECTIONS. One session read git log -S, found the commit that introduced the text, and concluded the session owning that commit had written it. That session had concluded the reverse, from having printed the entry in order to read it before editing a line of it. Neither held the right answer, and both had reasoned correctly from the evidence in front of them.

What settled it was asking. The session that wrote it confirmed authorship from its own record, with the detail that clinches it: its git add and git commit returned nothing to commit, working tree clean, with HEAD already at the other session's commit. Its draft title was <q>Six counting idioms&hellip;</q>, which is where the number in that title came from and why removing it was somebody else's call to make.

Two things the first account got unfair, corrected here because they change the risk and not just the tone. It said the text was <q>left uncommitted</q>, which is true and reads as careless: all three derived layers had been regenerated and all eight gates were passing before that session reached for the commit. What got swept in was vetted, gate-green text that lost a race by seconds, so the near-miss was on credit and never on correctness. And it did not write on a peer's say-so: told the file was clear, it fetched first, confirmed MERGE_HEAD gone, zero unmerged paths, a clean tree in sync, and confirmed the findings were genuinely absent after fetching. That is the stale-snapshot rule being applied rather than repeated, which is the opposite of what the first framing implied.

The finding never needed the name, and no session is named in it. git log answers a question about commits; authorship in a shared tree is not a question about commits. The fault generalises and the identity does not &mdash; but a reconstruction must say it is one, and the version of this paragraph that stated the account flatly stood for exactly one commit before the party who knew was asked.

The rule. A count is a claim, and this file already holds several entries where a measured number was right about its own arithmetic and wrong about what it measured &mdash; the register's block height, the contents-list heading threshold. This is the same failure one level down, in the instrument. Before reporting a count off markup, check it against a second method that does not share the first one's idiom, and if the two disagree, the disagreement is the finding rather than a rounding error. Three sessions agreeing is worth nothing if all three ran the same kind of pattern.

And it pairs with A stale snapshot is not evidence about the repo, in either direction. That one says a snapshot is not the repo, and that absence in a grep is not absence. This one says the grep may also be lying about what it found. Both faults were reported confidently, by sessions that were locally correct. Named rather than placed — this file reorders every time somebody inserts at the head of a section, and CLAUDE.md already records what a note binding itself to a position costs.

A stale snapshot is not evidence about the repo, in either direction (2026-09-10) Link to this section

Recorded because three sessions worked this repo on one afternoon, two of them hit this from opposite sides, and the near-miss is reproducible — not because anything is broken now.

What happened. The session fixing the Markdown verse flattening was told, in its brief, to move the entry The Markdown mirror flattens every poem on the site into prose from Open to Settled. It searched DECISIONS.md, found nothing, and reported that no such entry existed. It was right about its own tree and wrong about the repository: the entry had entered in be83959, which landed on main after that worktree was cut. It then merged be83959 — which brought the entry in — resolved DECISIONS.md by taking main's copy and inserting its own Settled entry above it, and did not re-check, because it had already concluded the thing did not exist. The log then asserted both that the bug was deliberately unfixed and that it was fixed, five hundred lines apart.

AND THE MIRROR CASE, an hour later, which is why this entry is not titled "absence". A third session described this working tree as mid-merge with eight unmerged paths and DECISIONS.md waiting to be staged, and declined to write an entry in case an append cost somebody their conflict resolution. Careful reasoning, and the merge had been committed and pushed two commits earlier. It was right about its snapshot and wrong about the repo, exactly as the first session was — and it was believing a state that was gone rather than doubting one that was there. Caution does not protect you from a stale premise; it just changes which way you are wrong.

Three rules, and the third is the one that cost the most to learn.

Nothing here changes a gate, and nothing can: no check reads the decision log or the register's prose for coherence, and one that tried would be a grader of English rather than a guard. The protection is the three rules above and a reader.


A blown-up tray mark is not a masthead, and two passes proved it (2026-09-10) Link to this section

Ryan asked for "a large version of the fox and hedgehog icon as the header art". Drawn twice, rendered at 368, 544 and 900px in both grounds, and refused both times.

Pass one: the mark drawn up with colour fills and features — rust pelt, marigold dome, ink stroke, plus an eye, an inner ear, a white throat bib and blocked feet. It reads as children's-book clip-art. Two reasons, and the second is the one that generalises: the flat colour masses fight the house register, which CLAUDE.md states as dark ink line art on vellum; and it would sit four inches above two Bewick wood engravings, whose fine black hatching makes a flat rust blob look like a sticker.

Pass two: the mark at scale, one ink colour, no features. Better, and the cabinet inversion is correct — but at 900px the construction shows. The mark is built from overlapping filled shapes with 20px tolerances: enlarged, the neck reads as a facet, the two ears as horns with a notch between them, the nose as a ball stuck on the muzzle, and the legs and feet as six rectangles. The hedgehog's thirty spines, right at 40px, become a cog.

The general lesson is favicon.svg's, running the other way. That rule says a favicon is judged at 16px because two earlier marks looked good large and died small. The converse holds and is less obvious: a mark drawn to survive 20px carries 20px tolerances, and enlarging it enlarges them. A masthead is a different drawing, not the same drawing bigger.

And the house masthead register is delicate, which two solid animals cannot be. Every other masthead here is thin moss stems, small lichen leaves, a small moth — sparse line. Two filled quadrupeds are the wrong weight for that page position regardless of how well they are drawn, which is why this is not a matter of another iteration on the same approach.

Settled: the animals are not the masthead, and the two Bewick plates carry them instead — which is what a mounted specimen is for, and they are better at it than anything drawn here would be. Closed on 2026-09-11 by drawing something else — see Two attention shapes, and the width a masthead is actually reviewed at. The page has a masthead now and it is not a fox and a hedgehog. The tray mark stays exactly as it is; nothing above changed it.


The Markdown mirror flattened every poem on the site into prose, and the fix is keyed on the line and not on its container (2026-09-10) Link to this section

tools/make-markdown.mjs listed span in its INLINE table as a bare wrapper, which is right for nearly every span on this site and wrong for the one that is not. <span class="l"> does not wrap words inside a sentence — it is a line, and queering.css has said since the Rossetti sheet that a poem's line breaks are the object being mounted; reflowed into prose it is a different poem. Ten pages were shipping stanzas as single reflowed paragraphs in the .md an agent fetches, and in llms-full.txt: Rossetti, Dickinson twice, Eliot, Douglas, Carroll, Shakespeare, Völuspá, Tam Lin, Yeats, Edith King's hedgehog and the Halliwell fox rhyme, the Stimpunks Manifesto, and Ryan's own reply verse on /wild-nights.

/two-cohabitating-modes was accessioned the same day and landed inside the fault. Its two poems — fifty-three lines — were flat in the .md from the hour the sheet was mounted, and the fix reached them on the merge without anybody touching that page. That is the argument for fixing the converter rather than the ten files: a generator fault is a fault in every page that has not been written yet.

The pages with no whitespace between their spans were worse than reflowed. Where the markup sets all the lines on one source line — .qe-lines does, on five sheets — there was no inter-line whitespace for the converter to turn into a space, so it produced againThe five unmistakable marks. Not a different poem: not words.

KEYED ON .l, NOT ON A LIST OF CONTAINERS, AND THE STYLESHEET HAD ALREADY PAID FOR THAT LESSON. The obvious fix is a hard break for .l inside .qe-poem or .qe-verse. That is the shape queering.css tried and abandoned: the display rule started as .qe-specimen .qe-lines .l, was copied to .qe-correction .qe-lines .l for the Miranda sheet, and then Sheet No. 8 put verse in a .qe-slip, where it inherited neither and printed four lines of Dickinson as one jammed run. The rule is unscoped now, and the comment beside it says a fourth component would have hit the same wall. A container list in the converter would have rebuilt that wall in the Markdown — and /flower-codes, named in the brief as affected, is .qe-lines inside a plain .qe-specimen and would have been missed by it on the first pass. A .l is a line of verse wherever it appears, in both files, for one reason.

This is not a break after every span, which would put line breaks through the middle of ordinary prose — the same error facing the other way. It is a break for the one class whose whole job is to be a line, and the ten files that changed are exactly the ten with a .l in them.

The marker is a trailing backslash, and two trailing spaces would have been erased after they were written. Markdown has both spellings of a hard break. The tidier at the foot of toMarkdown() strips trailing whitespace from every line, so the two-space spelling would have been emitted and then silently removed — a fix that reports success and changes nothing, which is worse than no fix. A backslash also survives the > prefixes that .qe-poem needs and .qe-verse does not.

It is emitted on the OPEN of the next line rather than the close of this one, so a stanza never ends on a dangling backslash. CommonMark renders a backslash at the end of a paragraph as a literal backslash, so the close-tag spelling would have put a stray \ under every stanza on the site.

.l-in re-indents in the source. Two leading spaces reproduce the 1896 compositor's alternating indent on Rossetti and on Tam Lin. A strict renderer may collapse them; the text an agent reads carries them, and that is the copy this file exists to protect.

search-index.json was already correct and did not change. make-search-index.mjs keeps a blockquote and a div.qe-verse as whole records, so the finding aid had never flattened a poem. Only the Markdown had — which is the drift the generator exists to prevent, arriving through the one door nobody had checked.

An easter egg may hide the door and may never hide the room (2026-09-10) Link to this section

Ryan asked for a fox-and-hedgehog mark in the top bar, "as a bit of visual whimsy and as an easter egg linking to the Two Cohabitating Modes page". CLAUDE.md forbids a hover-gated section mark on the grounds that hover hands a feature to mice and to nobody else, so an unlabelled control needed a reason it is not the same fault.

The reason is that nothing is withheld. .qe-modes-link is the only control in the tray with no visible word, and what that hides is the route, not the destination:

A sighted mouse user is the only reader who has to wonder what the drawing is for, and they lose nothing by wondering — the same route is in the footer of the page they are on. That is the difference from the hover-gated §, where the feature existed only under a pointer.

The rule to keep is the general one: an easter egg here may make a route discoverable rather than announced. It may never be the only route, and it may never be the only name.


The controls tray wraps, and it was measured before the fifth control went in (2026-09-10) Link to this section

At 375px the four existing controls filled the tray exactly — search link at x 20, the Reading disclosure ending at x 355, inside a 20px gutter. Zero headroom. The row is justify-content: flex-end, so a fifth item overflows off the left edge and takes the document's scrollWidth with it, which is the horizontal body scroll the layout rule forbids outright.

Settled: flex-wrap: wrap on .qe-controls. Two right-aligned rows on a narrow screen, a no-op at any width that fits.

Rejected: hiding the mark below a breakpoint. It would have withheld the feature from phones — and since the mark is the one route a reader discovers, removing it on the devices most people read on is where the loss would land hardest. Rejected: shrinking the mark on narrow screens. It is 41.6 × 20.1px already, and the mark was rendered at 16px during review: below about 24px wide the two animals stop being two animals.

The general lesson is the one this file keeps re-learning from the other direction. The tray had been full since the Reading disclosure shipped and nothing said so, because nothing measures it — check-overlap.mjs catches text on text, not a flex row running out of room. Adding an item to a fixed-width row is a measurement, not a markup edit.


Two specimens facing the same way, because nose to nose is a predation scene (2026-09-10) Link to this section

The first draft of the mark had the fox and the hedgehog facing each other, which composes well and says predator and prey — a fox nose to nose with a hedgehog is the fable, and the page it links to is about the two modes cohabiting. The drawing would have argued against its own page, in the corner of every sheet on the site.

Settled: both face the same way, which makes them a plate of two specimens — the site's own idiom, and no narrative at all. The fox is on the left with its brush sweeping into clear space; the hedgehog is on the right and smaller, because it is.

Three alternatives were drawn and refused, all judged by rendering at 16 to 180px rather than by reasoning:

And the near-miss worth recording: eight long spines are a stegosaurus. A coat is a mass of short spines, so there are sixteen, each placed on the dome's own normal and raked back — computed rather than hand-placed, which is the correction the lilac panicle already took. Do not reach for a handful of big marks when you mean a texture.


The "Four pages" sentence on the home page had been wrong for six pages (2026-09-10) Link to this section

Fixed in passing while adding the founding-papers entry. The home page's cabinet list said "Four pages that are not specimens" above a <dl> of six — /design, /changelog, /search, /ledger, /what-is-settled, /privacy. It now says "Six".

Worth a line here because of the shape of it, not the size. A hand-written count beside a hand-written list is a second copy, and it is the copy that rots — the same failure as a hand-kept contents list, which this site derives at runtime for exactly this reason. Nothing derives that sentence and nothing can, since it is prose. A count in prose beside a list is a thing to check whenever the list changes, and there are two of them on that page now.


The sheet is signed and the other two founding papers are not (2026-09-10) Link to this section

/mission and /manifesto carry no author in their JSON-LD: they are the collaboration speaking, and the manifesto is explicit that nine people wrote what it adapts. /two-cohabitating-modes carries "author": {"name": "Ryan Boren"}.

The asymmetry is honesty rather than an oversight. The claim that hedgehogs mean spiky profiles, punk and Disabled solidarity is Ryan's; the reading of the two poems was made in his session, from his sources. about.author stays absent, so check-metadata.mjs's conflation check has nothing to catch — the gate refuses a page naming the same person as its own author and as the author of the work it is about, which is a different thing.

The rule this settles for the group: a founding paper is signed when it carries a first-person claim somebody made, and unsigned when it is the house position. Signing is not a property of the group.


A component may mix the two type ROLES; it may never name a family (2026-09-10) Link to this section

Asked while setting one sentence of Max Alexander's Playful Manifesto as a broadside on the home page: should a playful block mix typefaces?

Yes, and the mix is between --qe-display and --qe-body, never between family names. The typeface picker works by reassigning those two custom properties on html. A font-family: 'Victorianna' written into a component is a face that none of the nine options can reach — nine controls, and one block on the page ignoring every one of them. Worse for the five display-only faces, where the reader has been handed Newsreader as the reading face deliberately: a named third family would put a fourth face on the sheet.

The two roles are a real mix and they cost nothing:

the reader's pickwhat the broadside shows
the defaultFraunces shouting, Newsreader carrying — two faces
one of the five display-onlytheir pick shouting, Newsreader carrying — two faces
one of the four that set bothone face, at six sizes

The last row is the point, not a shortfall. A reader who asked for one typeface gets one typeface; the setting degrades into their choice instead of overriding it. The play that survives in every row is the part that was never a family — size, weight, colour, indent, rotation, and Fraunces' SOFT and WONK where the picked face has them.

One word is exempt, and the licence is the drift rail's, not a new one. .w-form sets correct in the reader's own system face, for the reason .qe-drift-word--flat does on Sheet No.&nbsp;4: the notion being protested is an institutional one, and the institution's typeface is whatever the form was printed in. Semantic, not decorative — "it would look fun" is not this licence, and a second decorative hardcoded family would retire the first one's reasoning. Like the drift rail's, the joke disappears in plain view, where every face is that face, and that is correct.

Plain view keeps the composition and drops the ornament, which is the split .qe-cutup already draws and the answer to the second half of the question. Gone: the tilt, the tape, the shadow, the per-line rotations, the variation axes, and — by itself — the system-face joke. Kept: the line breaks, the six sizes, the indents and the three colours. Those are the setting rather than the decoration, and plain view has never removed information.

No motion, and the heading is the reason. The type plays, and the words do not move cannot introduce a specimen whose words move.


Two gates were reporting and not gating, and one guard covered only one of its two ends (2026-09-10) Link to this section

Both found while mounting Sheet No.&nbsp;10, and both had been true for as long as the things they guard have existed.

check-markup.mjs and check-sitemap.mjs need --check to exit non-zero, and this file's own checklist ran them without it. So every problem either has ever reported has shipped as advice. This is the third time the same trap has been paid for, and the previous fix is why it is worth an entry: the note added on 2026-09-09 about the contrast gate says outright that without the flag the tool is a report that exits 0 — and then fixed that one line and did not look at its neighbours. A fix applied to one instance of a class is how the class survives.

The repo has two opposite conventions and both are defensible on their own:

gating isgatesrun in the checklist
opt-in, --checkmarkup, sitemap, contrast, overlap, card-ordercontrast, overlap and card-order had it; markup and sitemap did not
opt-out, --no-gateaddresses, metadata, cachecorrect by default

Mixing them is the actual fault. A reader of either tool's --help would be told the truth; a reader of the checklist would run five gates and be protected by three. The checklist now carries the flag on all five opt-in gates. Reconciling the two conventions is a separate question and is not urgent, because the checklist is now right either way.

And check-markup.mjs's data-sheet guard covered one direction of two. Its own comment claimed the typo was "caught from both ends." It was not:

Two real faults were sitting in that blind spot with all eight gates green. Sheet No.&nbsp;9 had never been given a group, so its nine entries were unreachable from the index, and manifesto had none either. Neither is a typo, which is exactly why the existing existence check could not see them &mdash; both slugs are real pages, so the check that asks "does <token>.html exist" answered yes and stopped.

Proved by making it fail before believing it, per this repo's rule for a new gate: the missing direction was added first, reported both faults by name, and changelog.html went FAIL with --check exiting 1. Then the three groups were authored &mdash; No.&nbsp;9, No.&nbsp;10 and manifesto &mdash; and the same run went green. The check was never watched passing on a tree it had not first failed on.

A wide plate is 448px on screen, not 544, and the ladder is why it matters (2026-09-10) Link to this section

Measured while mounting the two Snark plates, after a comment was written asserting the wrong number and then checked.

The general lesson is the one this file keeps relearning: a max-width on a child of a narrower parent is a number that looks load-bearing and is not. .qe-wide was the first case, .qe-plate-wide is the second, and both were found by measuring the rendered box instead of reading the stylesheet.


A primary in a language we read beats a translation quoted through a summary (2026-09-10) Link to this section

The case. Sheet No. 9 rests on Deleuze's account of sense. The Logic of Sense is not sold as an ebook, Ryan does not have it, and Helen was asked whether she does. The proposal was to build on John C. Brady's Epoché reading of it and correct the sheet later against Deleuze.

Settled: no, and the sheet shipped with no provisional citation in it. Two things decided it.

One — build-now-verify-later has a boundary, and this was on the wrong side of it. It is fine when the later edit is an upgrade to a citation that was honest when it shipped; ATTRIBUTIONS.md already says re-reading is an upgrade rather than a precondition, and two sources on the Dickinson sheet ship confirmed bibliographically and not read. It is not fine when the later edit could change what the page claims. A section resting on a theory sourced entirely to somebody's summary of it is the second kind.

Two — the primary was reachable the whole time, in French. Logique du sens (Minuit, 1969) is openly readable at the Internet Archive; the two scans of Mark Lester's English are restricted to print-disabled patrons. So the sheet quotes the French and every English rendering on it is ours, labelled a gloss rather than a translation — the treatment the wyrd bið ful ārǣd half-line already gets on Sheet No. 4. Quoting Lester's English through Brady would have put a translator's authored choices in Deleuze's mouth, at a page number nobody here could open. A translation is itself somebody's authorship, which makes quoting one at second hand a sharper version of this site's characteristic failure rather than a milder one.

What the primary bought that a summary could not. Deleuze makes the Carroll identification himself — le sens est le Snark, p. 31 — so the pairing the sheet is built on is his and not our taste. And he grants that Snark is a portmanteau and then says it is one only secondairement ou accessoirement. A paraphrase reading "Deleuze calls the Snark a portmanteau word" would have been true and would have lost the argument.

The rule, generalised. Where a primary exists in a language somebody here reads, read it and gloss it in our own words, marked as ours. Do not quote a translation you have not opened, however standard it is and however carefully the secondary source handled it. Page numbers follow the copy actually read, and the page says which copy that was.

One consequence to remember rather than rediscover: adding a source later is not a correction. If Helen's copy arrives and the English gets cited alongside the French, that is a Mounted addition in the register and not a Re-determined with a marigold seam. Nothing was wrong. A gold join on a sheet nobody corrected is decoration asserting a fact, and it makes the real mends unfindable.


Settled. Ryan noticed the footers had drifted apart. A survey of all seventeen found three shapes and a hole:

shapepages
Long — five cabinet links as authored gloss sentences, 6–8 paragraphs15, 107–226 words
Compact — a row of three, plus two links still as sentences, no licence line1 (/monotropa-uniflora)
Bare — identity and licence only1 (/index, deliberate)

And every footer on the site was missing /ledger and /what-is-settled — both had addresses, both were listed on the home page, and neither was reachable from the foot of any page. That was the real defect; the inconsistency was how it stayed invisible.

Now: a row of short links, the collaboration line, that page's own licence sentence, and on sheets one sourcing sentence. 32–98 words instead of 107–226. The home page keeps its bare footer, because .qe-furniture sits two paragraphs above it with the same seven pages and their glosses.

The glosses were the thing worth dropping. Five authored sentences restated on sixteen pages is eighty copies of editorial prose free to drift, and drift is exactly what happened. They still exist once, on the home page, which is where this repo already said those sentences live.

Short nav labels are a second name, and that is fine here. Colophon, Register and Decisions are not what those pages call themselves. A row of links and a page title are different registers; the rule against a second name governs the group headings, where the name identifies a set. /what-is-settled keeps its address.

Sourcing does not move into .qe-provenance, and that was the interesting question. Ryan asked whether the per-sheet attribution prose belonged there. It does not:

So the footer keeps one sentence — every quotation here was read in the work it comes from, and is logged in the attribution ledger — and the trail lives where it already lived. What is lost is per-sheet detail like read in three separately scanned copies; that is in the ledger, and the sheets that said it were saying it a third time.

One thing to check by eye. /monotropa-uniflora had no licence line at all — the compact footer had dropped it — so it was given the wording two comparable sheets already use: Our words licensed CC BY-SA 4.0. Everyone else's belong to them, or to nobody. Accurate for what that sheet quotes, but supplied rather than authored.

Back to the top, drawn as growth rather than as a chevron (2026-09-09) Link to this section

Settled. Ryan wanted a way back up after finishing a piece, and asked for a footer illustration of grasses whose taller stems form an arrow, with Scroll to top above them.

The arrowhead is a seed head. A chevron drawn over grass is a UI arrow in a costume, and this site already has a native idiom for "up": growth, stems drawing themselves on from the ground. Two tall blades arc up and converge at the middle stem's head, and the silhouette is an arrow without one being drawn. The first attempt put two short awns on the head and read as a small figure with its arms raised — looked at, and redrawn, which is what this repo's own rule about judging a drawing at its shipped size is for.

No script, and no new motion. A plain anchor scrolls; scroll-behavior: smooth is already set once and already switched off under prefers-reduced-motion. The mark wears .qe-botanical, so the blades draw themselves on with the same gating as every other drawing here.

A note on how this one was reviewed. The first pass treated the phrase Ryan used to describe the look — a grassy waste garden — as though it were about to be printed on the page, and refused it on attribution grounds at length in four files. It was never going to be printed: the footer says Scroll to top, and a drawing of grass quotes nobody. Design vocabulary in conversation is not a publication, and reading it as one makes the work harder to talk about for no gain. ATTRIBUTIONS.md governs what the site says to a reader. It does not govern how we describe a feel to each other.

main gained tabindex="-1", and it is the quiet half of this change. Two in-page links now aim at that landmark. A landmark that cannot take focus leaves a keyboard reader's focus in the footer while the page scrolls away from it, so their next Tab resumes at the bottom of a page they just left. Verified after the change: activating the link scrolls 9,952px, sets the hash, and moves focus to main. The skip link has wanted this since it was written and nobody had noticed, because the failure is invisible to anyone using a mouse.

Every sheet gets a contents list, and one of them puts it in an odd place (2026-09-09) Link to this section

Settled. Three of the eight sheets had no On this sheet list — Nos. 1, 2 and 7 — and no reconstructible reason for the gap. They run 2,045 to 3,098 words against 2,495 to 5,018 on the five that had one, so the bar the existing pages set was already cleared. All eight now have one, plus /design and /mission: ten pages.

The opt-in stays in the markup. Nothing derives the list from a word count, because which pages want one is an editorial call. What is now settled is only that the answer for a sheet is always yes. The pages that decline all have a stated reason: the home page, whose plate is already a contents list; /changelog, whose headings average 148 characters; and the four pages with two headings each.

"After the lede" turned out not to mean "before the first heading." Checked before placing anything: five of the existing lists carry opening prose after them — /wild-nights nineteen blocks, /invention-of-normal thirteen. The list is front matter for the sections, and the lede is not a section.

/coming-to-terms was the exception for a week, and then stopped being one. It had no lede at all, and every one of its six headings sat in the 2026 commentary, so a list at the top would have named six sections beginning a fifth of the way down and said nothing about the essay — a contents list misrepresenting its own page. It went after the register note instead. The note said the essay needed a heading of its own before it could be listed, and that this was a decision about Ryan's 2022 text that nobody should take on the way past.

Ryan took it on 2026-09-09: the sheet now has a lede and the essay is a section called Against My Grind. Three things about that are worth keeping.

A rail of the page's own headings, and both contents lists shown at once (2026-09-09) Link to this section

Settled, and the interesting half was overruled.

Every <h2> here has carried an authored id since the contents list was built, so /#what-grows-here and /#the-cabinet-itself were already addresses. What was missing was the affordance: the plate is eight screens down the home page and the cabinet fourteen, and nothing on screen said either could be jumped to. A link nobody can find is close to a link that does not exist — the objection this site makes to an untraceable quotation, arriving as a navigation problem.

.qe-rail is fixed in the left margin above 64rem and absent below it. Same derivation as .qe-contents — the page's own headings, in document order, labelled with their own words — through one builder in queering.js, because a second loop would be a second place for the three heading exclusions to be got right.

IT COLLAPSES TO TICKS, AND THE HEADINGS COME UP ON HOVER. The first build showed every label all the time; Ryan wanted the reference site's behaviour, which is a column of short rules that becomes a list of headings when a pointer enters it. This is not what "no scroll-spy" was refusing — that refusal is about a mark which tracks the reader down the page on its own, unprompted, forever. The rail moves only when a reader asks it to. Nothing here follows the scroll.

The labels stay in flow at opacity: 0, and that one decision is what makes it safe. The reference site puts each label in an absolutely positioned pill so its ticks can sit at an even 20px pitch. Refused here, by working out what the gates would see: revealed for measurement, those pills would lie over one another and check-overlap.mjs would report every label sitting on the next. Left in flow, the revealed state is exactly the expanded rail already measured clean at 1280px. The cost is paid in the collapsed state — a row is as tall as its own label, so the ticks are not evenly pitched. That is one row on the home page and three on /flower-codes; a hand-ruled pitch suits this house, and overlapping labels would be a defect.

THE TICKS CARRY THE SHAPE OF THE PAGE, AND THAT IS WHAT EARNS THE UNEVENNESS. Collapsed, the rail was a column of identical rules at an uneven pitch — uneven because a row is as tall as its own label. Ryan's read was that it looked like an imperfection to lean into. The problem with leaning into it as it stood is that asymmetry only reads as asymmetry against a norm, and with nothing else varying the pitch just read as an accident.

So the ticks were given the norm to deviate from, and the deviation is inherited from the sheet rather than invented: each tick is as long as its section is tall, normalised 9–32px across the page. The rail became a small scale drawing of the document — you can see which section is the long one before reading a word of it. Checked on /wild-nights: the 3032px section draws 32px, the 1635px section draws 9px, monotonic across all eight.

That it means something is the licence for it, not a bonus. A tick whose length varies looks like it encodes something, and this repo refuses decoration asserting a fact it does not have. Four options were rendered against the real stylesheet before choosing — flat, weight-only, lean-only, and both — and the one that varied length without meaning was refused for exactly that reason.

The lean is the other half and it claims nothing, which is what makes it free to be ornament: up to 3.2° per tick, walked by the golden angle so it is deterministic rather than random. The same sheet draws the same rail every time, which is what lets a stain be a fact about one sheet rather than a dice roll per visit. It is the wonk axis this site already runs on its type, applied to a rule instead of a letter.

They part company under html.plain: the lean goes, the lengths stay. Plain view removes decoration; it has never removed information. That distinction is the whole argument for splitting the effect in two rather than shipping one varying tick.

Measured after document.fonts.ready. A webfont swap moves section extents, and a rail measured against the fallback is measuring the wrong sheet. Nothing else needs re-measuring — main is capped at 34rem and the rail only exists above 64rem, so the measure never reflows while the rail is visible. A page with no variation in section height gets a flat 22px instead of a stretched range: there is no scale to draw, and stretching a flat range would invent one.

THE RAIL GETS ONE TERMINUS AND NOT A SCATTER OF DOODLES. Ryan asked whether small doodles above, below or around the rail would add to the handwritten feel, and flagged the risk in the same breath: that it might compromise the Ma. Both arrangements were drawn against the real stylesheet and looked at, and his instinct was right about the scatter.

What survives is the version that is not an addition at all. The rail's rule already reads as a stem, and a stem that simply stops is the only unbotanical thing about it. So it now ends in a terminus — two leaves and a bud, continuing the line rather than sitting beside it, pulled back past the nav's padding to meet the border. It occupies margin nothing else wanted and adds no second object to the page. 28px, stroke only, moss.

It wears .qe-botanical, so the growth idiom is inherited rather than restated: the stem draws itself on, the leaves unfurl, and both were already gated on prefers-reduced-motion and already kept-but-stilled under html.plain. Only the size is new, exactly as with the moth — a second copy of that idiom would be a second thing to keep in step. It takes --qe-moss and so follows the ground with no cabinet rule of its own; verified in both, and at 0.85 opacity in plain view.

The unguarded-ornament problem is real and is why this is small. check-overlap.mjs catches text on text, so a drawing in the margin is measured by nothing — it could drift onto the measure at some width and no gate would say a word. Keeping the mark inside the rail's own box means the rail's own measured clearance covers it. Anything free-floating out there would need measuring by hand at every breakpoint, which is a maintenance cost this site has not agreed to pay for decoration.

Hover-gating is only allowed because every other way in stays open. This repo already refuses a hover-gated section mark, on the grounds that hover hands a feature to mice and to nobody else. The rail is exempt because nothing is actually withheld: the heading text is in the DOM at all times, so a screen reader has every link name whatever the opacity says; :focus-within brings the rail up when a keyboard arrives in it; @media (hover: none) never collapses it on a device that cannot hover; and plain view never collapses it either. Take any one of those away and the collapse becomes the thing this file forbids.

BOTH LISTS SHOW, AND THAT WAS RYAN'S CALL AGAINST THE RECOMMENDATION. The recommendation was to hide the in-body list wherever the rail is up, on the grounds that this file already refuses a contents list for the home page because two competing navigational lists is a defect. Ryan overruled it: he wants both. The refusal still stands and does not reach this case, and the reason is worth keeping because it is the argument that makes the overrule right rather than merely instructed —

So the design work went into making them unmistakably different objects instead of into hiding one: the rail is smaller, moss rather than rust, unnumbered, unlabelled, and set out past the measure in space no line of text ever occupies. It is unlabelled because a visible heading would be a third copy of the words "On this sheet" and the one free to drift; the aria-label is authored in the markup, once per page.

The register does not get one, for the reason it has no contents list either: 28 headings averaging 147 characters, longest 226, which in a 12rem column with no truncation allowed is a four-thousand-pixel rail.

No scroll-spy, unchanged and for the same reason — a mark that moves as the reader scrolls is a second thing on screen that never settles, and a rail is where that costs most. :target still marks where a reader landed.

THE BREAKPOINT SHIPPED AT 77rem, RYAN COULD NOT SEE THE RAIL AT ALL, AND THE NUMBER WAS WRONG TWICE OVER. Zen's tab sidebar takes its width out of the viewport, so a 1440px laptop was arriving under 1232px and the rail never appeared. Reducing the number turned into finding out it had never been derived correctly.

Measured rather than calculated, which is what should have happened first: at 1024px the leftmost thing inside main across the art-heavy sheets is 277–288px, against a rail ending at 172px. That is ~108px of real clearance where the old sum was defending 24px. 64rem is that figure with slack, and it is 208px better than shipped — enough for a 400px sidebar on a 1440 screen. Boundary checked both sides: display: none at 1023px, block at 1024px. A 9rem column would reach further still and is refused: at 144px a heading wraps to five and six lines and the collapsed pitch gets wilder than the labels are worth. Vanishing below the breakpoint is also what satisfies WCAG 1.4.10 — at 400% zoom the viewport is 320px wide and the rail is already gone, so it cannot eat the height a reflowed page needs.

Two costs came out free, and both were checked rather than assumed.

The hit-area rule was got wrong twice, in one control.

An eighth gate: check-card-order, and why the port is a rewrite (2026-09-09) Link to this section

The plate shipped 1-6, 8, 7 and /the-tempest shipped 4, 1, 2, 3. All seven other gates passed both, and none was wrong to — order is not colour, position, freshness, routing, structure, headers or the manifest. The house rule is to port a Star Stuff check when the failure becomes possible here; this one had already happened twice.

The port could not be a copy. Upstream checks ascending order within each series, because a collection there interleaves Zine and Field Guide numbers deliberately. This site has no series: one accession run, kind chip as a label. No. 8 is a Wall and No. 7 a Reading, so under the series split the broken plate is two perfectly ascending sequences and the gate would have certified the page that prompted it. Verified by patching the split in and watching it report ok · 0 problem(s), then taking it out and watching the same plate fail. Recorded because the next port will look equally straightforward.

Three rules, each made to fail before being believed: ascending within a grid (the restored plate); cards outside any grid (one card moved out); every card agreeing with the plate about a sheet's number and kind. Plus the empty-authority guard — break the card selector on index.html and it reports NOT MEASURED rather than clean, which is the overlap gate's empty-pass lesson arriving in a second tool — and --check both ways, exit 1 with, exit 0 without.

Rule 3 earned its place on its first honest run, the same way the upstream tool's second check did. Fifteen cards disagreed with the plate: /404 filed /coming-to-terms as a Reading when it is Ryan's own essay, and /monotropa-uniflora as a Reading where the plate says Wall; and the No. 8 accession had written its kind chips with articles — "A wall" on seven pages, "A reading" and "An essay" through its own nav — against bare nouns on the fifty cards before it. The plate is the authority and not the majority: a vote among sibling navs would have let a fault copied onto seven pages outrank the one page whose subject is what the cabinet holds.

Where the plate is silent, mutual agreement is still required. It does not card itself, so nothing could arbitrate / being "Plate" on one nav and "The plate" on another. That is reported apart and counted once per address, not once per page, because printing it twice invites somebody to fix whichever file they opened first. No other kind chip carries an article, so "Plate".

Refused: checking the plate against tools/pages.mjs. They agree today, which is why it is tempting. They are two different facts — the number records when a sheet was accessioned, the group records the order a reader should meet the pages — and mounting Sheet No. 9 third would diverge them legitimately. Coupling them makes an editorial decision a build failure.

Still not ported: check-classes, check-sheets, check-embeds. check-classes is the one closest to the bar — a class with no rule renders black and no gate here catches it, and it happened twice in one afternoon — but unlike this one it needs a browser, because it wants the real cascade.

The ledger and the decision log became pages, generated backwards (2026-09-09) Link to this section

/mission aim 12 claims the site works in public with the working-out left in, and pointed at two files on GitHub because they were reachable no other way. An aim whose receipt is on somebody else's website is the thinnest receipt on that page. So ATTRIBUTIONS.md is now /ledger and DECISIONS.md is now /what-is-settled.

Generated, not transcribed, and the direction is inverted on purpose. Every other generator reads a page's landmark and writes the Markdown beside it. make-records.mjs reads the Markdown and writes the page body between markers, because these two are working documents: the credit-source skill appends to one, every session that settles something appends to the other. Making the page the source would mean editing a ledger entry in HTML — which is how a ledger stops being kept. Either direction is fine. Two hand-kept copies is the thing this house is organised against.

THE SLUGS ARE A FILESYSTEM FACT, NOT A PREFERENCE. macOS is case-insensitive by default. /decisions is decisions.html; make-markdown.mjs writes <name>.md beside every page; decisions.md is DECISIONS.md. The generator would have silently overwritten its own source with a round-tripped copy of itself, on the first run, with git as the only way back. attributions.md collides identically. Checked with a temp directory before a line was written. /ledger is the site's own name for that file in every footer it appears in; /what-is-settled is the other file's own opening line.

The proof was wrong more often than the converter, which is the interesting part. The tool compares each block's words against the rendered text before writing. It fired five times: once on a real fault — **The lower-case *g* is kept**, emphasis nested inside emphasis, where the inner pair is a letter being quoted and the first pass refused the nesting rather than reading it — and four times on the proof itself, which was stripping a list bullet, a table's pipes, the underscores out of Photon Pulse_he_him (a study participant's pseudonym the converter was right to keep), and the {#anchor} out of a pinned heading. A guard that cries wolf gets relaxed, so the proof was rewritten to model the converter rather than approximate it.

Heading ids are slugged, against the house rule, with an escape hatch. The rule is that an id is authored because a slug dies when the heading is reworded. It cannot be met by a generator over ~120 entry headings with nowhere in Markdown to author one. So ### Title {#anchor} is honoured where written and a slug is used where it is not — one line to pin an address somebody has actually shared, no schema. Two headings that slug alike stop the run naming both, because check-markup.mjs would report the duplicate id as a symptom on a generated file while only this tool knows the two titles.

Both walkers learned pre the same afternoon, and the Markdown one needed more than the tag: its text handler collapses whitespace and escapes punctuation, which is right everywhere except inside a fence — the first output put a shell command and its continuation on one line with backslashes through the quoting. The search walker indexes the block rather than skipping it; a command in the decision log is content.

The search index roughly doubled and that is stated rather than hidden, in the register and here: 154 KB gzipped to 249 KB. It is fetched after render with max-age=0, so an unchanged index is a 304 and no bytes move — the cost is paid when it changes, not per visit. Both records were indexed rather than only the ledger, because a decision nobody can search is close to a decision nobody published. /search's lede moved in the same commit, for the third time a page that binds us has had to.

Resolved the same day: both pages now index their own entries. .qe-entry-index, back matter, filled by queering.js from each page's own headings — 55 on the ledger, 71 on the decision log. The served container is empty because a generated index of 121 headings would give the mirror and the search index a second copy of every one, which is the reason .qe-contents is built at runtime and not written down. Group headings are derived here where the register's are authored, because these are clones of h2s already on the page rather than editorial words; they are marked up as paragraphs so the outline does not gain a shadow contents of duplicates. Two columns above 34rem, one below. No REVEAL line, confirmed by counting measured elements rather than by reading reveal.mjs.

/design, /changelog, /search and /privacy were reachable only from the footer of every page, which is where a site puts what it hopes nobody needs. A site that publishes an attribution ledger and a privacy policy should not file both under fine print. They now have a section at the foot of the home page, inside main.

The name was not invented. tools/pages.mjs has called this group The cabinet itself since the finding aid shipped, and /search's manifest and /llms.txt already show that heading to readers and to agents. Picking anything else — Off the plate, The workroom — would have been a second name for a set that had one, which is the drift this repo keeps paying to avoid. Ryan chose it from three.

No card treatment, and that is the whole design. A card would file these with the eight readings and none of them is a reading of anything. It is the bare tier: space only, no fill, no box. The plate above does the ranking and this list agrees by declining to compete.

Back matter, not front matter — the correction the register already paid for when a contents list at the top of /changelog delayed its first entry by three and a half screens. It sits last inside main, where the four links it replaces already sat.

A <dl>, so the Markdown copy keeps the pairing. Each entry is a name and a gloss on it; the converter writes a term and its definition rather than eight loose lines.

It is inside main, which the sibling-nav rule forbids and this does not break. That rule stops one sheet's navigation being indexed as another sheet's content. A list of the site's own pages, on the site's own index page, cannot do that — the same reasoning that lets .qe-contents sit inside main.

The hit area was measured, because nothing here measures one. A <dt> that is entirely a link is not an inline link in a sentence, so WCAG 2.5.8's inline exception does not apply, and the ink alone is 23px tall. Padding takes each target to 45.2px, confirmed in the browser at 1280px and at 375px, with 88px of clear space between adjacent targets. The padding is netted out of the spacing scale so the list does not start 11px below every other block on the page.

Only the home page's footer lost the links. Everywhere else the footer is still the way there; on the home page they are two paragraphs above it.

One embedded recording, and the privacy page it cost (2026-09-09) Link to this section

Ryan asked for a click-to-load embed of Eliot reading The Waste Land, under the lilac, because he and Helen listen to it together. Built, with the whole cost stated.

What it broke. /privacy claimed, in five places, that the site makes no third-party requests — including the line "It was the only one," written that morning about the Google fonts. A privacy policy is a binding statement of practice, so all five moved in the same commit that made them false. The replacement is not a smaller boast, it is a more precise claim: reading a page reaches nobody, and there is exactly one place you can choose to reach somebody.

The design: a facade, not an embed. The served page holds a poster we drew and a plain link. Nothing touches Google until a press. Measured, not asserted — non-local hosts contacted on load: []; after the press: exactly www.youtube-nocookie.com. YouTube's own thumbnail was refused because it would be a request to i.ytimg.com on every load, which is the Google-fonts failure in a hat.

A third script, for the reason there was a second. queering.js may never put content on a page; this script's entire job is to put somebody else's content on one. That is the strongest possible version of what the boundary prohibits, so it got its own file rather than a widened boundary — the same call queering-search.js got.

youtube-nocookie.com is not anonymity and the page says so. It does not set advertising cookies on load. The IP address still reaches Google. "No cookies" and "no tracking" are different claims and only the first is made.

What is unresolved, and is Ryan's call, not ours. The upload is by a channel called tim24frames. Eliot recorded the poem more than once; we have not established which reading this is, or who holds the recording, and the channel is unlikely to. Embedding is legally distinct from hosting — the bytes come from YouTube and takedowns are theirs to honour — but on a site that publishes an attribution ledger, an unattributable recording is a genuine wart. The caption says exactly that rather than smoothing it, and if the upload disappears the facade degrades to a dead link rather than a broken page.

The gate reads our JavaScript now (2026-09-09) Link to this section

check-metadata.mjs enforced "no third-party requests" by scanning HTML attributes. It would have passed this page. The request lives in a script. A gate that cannot see where the failure would occur is a gate that certifies the failure, so it now also:

All three were made to fail before being believed. The first found a real fault on its first run: the script contacts www.youtube-nocookie.com and the policy named the bare domain. The third fails twice over — make-markdown.mjs throws on the unknown tag before the new check is reached, so the converter's "teach me or I drop content" rule turns out to catch a privacy regression by accident.

The lilac bush, and three things it cost (2026-09-09) Link to this section

Ryan's shrubs, drawn from his photograph, standing above the footer on the home page — the second lilac-and-black drawing here and the first drawn from a photograph rather than from another artwork. The page had just borrowed a colour from a song and had nothing of the actual plant in it.

The vase habit is the whole read. Many slender woody stems from one clump at ground level, bare for the lower third, fanning into a dome half again as tall as they are. Two drafts put the bare stems at more than half the height and produced a hand fan. The proportion was measured off the photograph in the end, not guessed.

Even coverage needs stratification, not randomness. Ring placement left the middle hollow and read as a wreath. Uniform random sampling clumped into two lobes with a hole between them — which is what forty random points actually look like, and worth remembering the next time random is reached for when even is meant. Staggered rows inside the ellipse give even coverage by construction.

85KB raw, 9KB compressed, and the optimisation is refused. Seven hundred circles. The home page went 43KB → 143KB raw and roughly 7KB → 22KB over the wire; measured before shipping. Defining the leaf and floret once and referencing them with use saved 20KB raw and rendered every clone black: outer stylesheet selectors do not cross into a use shadow tree, only inherited properties do. That is a fraction of a kilobyte compressed for a styling path that fails silently, and the refusal is written beside the component so the next person has the same idea and stops.

Print is an engraving, deliberately. Every floret prints as an open circle in line, tone carried by overlap rather than ink coverage. The alternative was three flat greys, which would have made the design sheet's claim that these drawings print as line work false. Verified under print emulation — where a second fault appeared: the print block sat above the base rule at equal specificity, so the caption printed moss-green. Source order decides; the print block goes last.

check-classes is now the strongest port candidate (2026-09-09) Link to this section

A class in the markup with no rule in the stylesheet renders with SVG's default black fill and nothing here notices. It happened twice while the lilac was being drawn: the generator emitted puff-pale before the stylesheet knew the name, and the use experiment above put .leaf and .floret somewhere selectors could not reach. Both were caught by looking at a render, which is not a gate.

The house rule is to port a check when the failure it catches becomes possible here. It is not merely possible, it has now happened twice in one afternoon. Star Stuff's check-classes is the next port, and the thing it needs to learn that Star Stuff's copy may not know is that a class inside defs referenced by use is not stylable from the outer sheet — a rule with a matching selector is not proof the element is styled.

The moth is an homage, and the four things it cost (2026-09-09) Link to this section

Ryan's idea: the cover of Nick Walker's Neuroqueer Heresies puts a human brain where a swallowtail's body would be, so put the Earth there and you have this site's name as a drawing. The colours are Ezra Furman's — we wear the lilac and black. Both credits are in the figure's own caption and in ATTRIBUTIONS.md.

Placement: the foot of "Queering is a verb", not the masthead. The header spray was not the thing to replace, and the moth is an argument about that particular section — the verb, and our extension of it. It is the first drawing here that is neither a masthead nor a corner.

Surface: bare. Our drawing, our caption, so it is the default tier. A dark-ground card was drafted (lilac line on near-black, identical in both grounds, closest to the book cover and to the song) and refused: a black panel on a vellum sheet is a fourth surface, and the three-surface rule exists so a reader can rank a panel without reading its label. Revisit only if something else genuinely wants a worn-card surface, in which case it is a rule amendment with a second use case behind it, not a one-off.

Two new decorative tokens, taking the decorative five to seven. --qe-lilac and --qe-lilac-pale. A wash and the thing washed onto it cannot be one value — the same reason --qe-paper has a --qe-paper-deep. The alternative considered was reusing --qe-violet for the forewing and adding one token, which would have saved a line and changed the drawing that was actually approved. The pale one goes darker in the cabinet, because in daylight it is the recessed thing.

The black inverts, and that is not a compromise being hidden. "Black" is --qe-ink, so in the drawer the outline and the continents come up cream. The song says lilac and black; the ground rule says the lightest thing text sits on flips, and a literal black line on dark warm brown is a line nobody sees. The only version that would have held true black in both grounds is the card that lost on the surface rule.

The coastlines are projected, not drawn, and the reason is funnier than it is technical. Three passes of hand-drawn continents came out as symmetrical dark blobs either side of a central meridian — a Rorschach card, which is to say a brain. A picture whose entire point is that the Earth is where the brain was cannot have a middle that reads as the thing it replaced. They are now coarse lat/lon outlines through an orthographic projection centred on 25° W, 12° N, with far-side points pushed onto the limb rather than folded back across the disc. Africa is unmistakable at a 40px radius, which is the size that matters.

No tails, after four attempts. Straight down they read as legs; swept out, a bracket; curled in, a moustache; merged into the hindwing path, a boot. A broad fanned hindwing and a feathered antenna are what say moth. The cover's tails say swallowtail, which we are not, and the caption carries that reference so the drawing does not have to fake it.

One process note worth keeping. The first four review screenshots showed a moth with no wings. Every wing is inside a .sprout, which starts at opacity: 0 and unfurls on a delay, so a screenshot taken half a second after load photographs an animation that has not happened. The gating is right; the reviewer was early. Anything that screenshots a drawing here has to wait out 0.55s + i × 0.075s plus the unfurl.

check-overlap is ported, and two faults in it were found on the way (2026-09-09) Link to this section

Ported from Star Stuff because a corner-floated accession stamp was designed, measured and refused partly because nothing here could see it land on the prose. Refusing a design for want of a gate is a reason to build the gate, and the gate now catches that exact design — 7 collisions on Sheet No. 2, span.qe-stamp-no "Sheet No. 2" sitting on the masthead's own a "Queering Earth". That is how it was proved rather than assumed.

Not a copy. REVEAL/UNREVEAL were extracted to tools/reveal.mjs and the Chrome client to tools/cdp.mjs, both shared with check-contrast.mjs. REVEAL is the one that mattered: it is the list of things a page builds at runtime, it is editorial, it GROWS, and its own comment tells the next author to add to it. Two copies is a component one gate learns and the other does not — the failure html.mjs and pages.mjs already exist to prevent. cdp.mjs earns its place on evaluated() alone, which turns an in-page exception into a loud failure instead of a flawless report about a page nothing measured. Both extractions were proved output-neutral: check-contrast --check printed a byte-identical report before and after.

TWO FAULTS IN THE IMPORTED TOOL, both fixed here and neither reported upstream from this repo, because Star Stuff is not edited from a session in this one:

  1. The clip walk started at el.parentElement, so an element clipping its own overflowing text was never a clip host and the fault was invisible. Found by probing why .qe-sr produced no phantom clip: it is a 1px box with overflow:hidden holding a 288×39px line of text, and nothing reported it because the walk stepped over the very element doing the clipping. Fixed to start at the element. On this site it changes no finding today — the only overflow:hidden in the stylesheet is .qe-sr's own, and that is excluded as invisible — but it is what makes the clipped proof possible at all, and the proof names span.qe-provenance-label as its own clip host.
  2. locate() reported page for the case the gate exists to catch. It walked up the ancestor chain looking for a preceding heading, and an absolutely positioned block is a child of main, so the one finding that most needed an address got none. Now it walks backwards over real document order and returns the nearest authored heading id — which always exists here, because every h2 carries one by house rule.

Three things about this site that changed the port:

Rotation needed nothing, which is worth knowing rather than rediscovering. This site leans type in fifteen places, and getClientRects() on rotated text returns the axis-aligned box of the rotated quad — the stamp's bottom line is 11px of type whose AABB is 29px at 7 degrees. INK_RATIO already handles it: the shrink takes min(rect.height, em × 0.8), so an inflated AABB is discarded in favour of the em box. The imported constant was already the defence. If a component ever leans far enough for that to stop holding, the fix is to measure the rotated quad, not to widen the tolerance until the noise stops.

The print pass was added the same day, and it is not in the upstream tool. Star Stuff defers print collisions to check-sheets.mjs; this repo has no paper gate, and paper is the medium this house has already been burned by. Three passes now: screen, Letter, A4.

The viewport moves, and that is the entire reason the pass is worth having. check-contrast.mjs emulates print media at 1280px and is right to — it measures colour, and colour does not reflow. A collision is a position, and this stylesheet sets main { max-width: none } in print, so the text runs the full width of the sheet. Measuring that at 1280px measures a line length no printer produces. The counts are the evidence: /changelog is 4,884 text boxes on screen, 3,567 on Letter, 3,604 on A4. Both papers, because those last two numbers differ — 22px of width is enough to rewrap a line and move a hand-placed mark, so picking one and calling it "print" would be this pass's own mistake at a smaller scale.

Proved in four ways, and the fourth was a surprise. A print-only collision reports 0 on screen and 3 on each paper; a screen-only collision reports 7 on screen and 0 on paper, which is what proves UNREVEAL and the media switch do not leak. Exit code 1 on a paper-only fault. And the empty-pass guard, which is per pass rather than per page: a stylesheet that renders nothing on paper measures zero boxes there while measuring hundreds on screen, and the run reports the page as NOT MEASURED and names which passes were blank. That is the 44-blank-pages fault, and it would not survive this gate — which was not the reason the guard was written.

Pagination is the honest limit. Chrome's print emulation reflows to the width but does not break the document into sheets, so a collision that exists only because two blocks land either side of a page break is invisible. break-inside: avoid on .qe-accession-block is there because pagination is real. Reaching it means extracting text positions from Page.printToPDF, which is a different tool rather than a flag on this one.

The accession stamp says Queering Earth, and the fade is on the ring (2026-09-09) Link to this section

Ryan saw the oval stamp on a scanned sheet from the Ada Hayden Herbarium at Iowa State University and asked whether we could do the same, faded, for the sense of age. Two things were genuinely open and were put to him; both answers below are his.

What the stamp claims custody on behalf of: Queering Earth alone. The Iowa stamp names an institution and its parent, so the obvious move was Stimpunks and More Realms on the lower line. Two custodians also did not fit the oval — at that size the line crossed its own ring — but the layout was not the argument. A stamp asserts a single custodian, this site is a collaboration between two organisations, and Queering Earth is the one name true of the whole of it. The two are credited where credit is a sentence and not a mark.

What goes in the lower line: the accession date. The alternative was the custodians, per the reference stamp. The date makes the mark an accession record rather than a nameplate, which is the entire justification for having it.

The number had to be real and it happens to be. Ada Hayden's 497892 is a row somebody can go and read. A six-digit number invented here would be a gold join on a sheet nobody corrected, and on a site whose one stated correctness requirement is attribution that is the worst available place for that failure. The sheet number and the mounting date are both entries in the register, so the stamp asserts nothing new — and no sheet stated its own number inside its own landmark before today, so it duplicates nothing either.

The fade could not go on the letters, and this was measured before anything was drawn. --qe-lichen is 2.15:1 on paper — the figure this repo already uses as its injected FAIL — and --qe-verdigris is 3.42:1. Neither clears 7:1 or the 4.5:1 large-text floor, so no token here can make a letter faint and permissible at any size. The letters are --qe-moss and the age is carried entirely by the ring. That is the standing house rule, and it turns out to be what a real understamped impression looks like anyway: the outline breaks long before the letterforms do. Nothing was traded away to get the ink legal.

Three things were found by looking rather than by any gate, and all three are the reason to keep looking:

The corner-floated version was refused. A stamp belongs in the corner of a real sheet, and an absolutely positioned one lands on the prose at a narrow width, at 400% zoom, or under a long heading — which nothing here can currently see happen. Star Stuff has check-overlap for exactly that, and the house rule is to port a check when its failure becomes possible. Not floating the stamp is cheaper than porting the gate.

The stamp is not a link and not indexed. The provenance line beside it already points at the accession, so linking the number is a second tab stop landing on the same anchor. And indexed, eight stamps put eight near-identical records carrying the site's own name into the finding aid — which is precisely why .qe-masthead is already skipped. It stays in the Markdown siblings, where there is no ranking to crowd.

Search is a page, a file, and a refusal (2026-09-09) Link to this section

Ryan asked for search. Three things were genuinely open and were put to him; all three answers below are his.

Where it lives: a /search sheet, and only there. A field in the masthead of every page has better discovery and costs a markup change on thirteen pages and an argument about whether the field is furniture or content. Inline live search everywhere was the third option and the worst fit: it fetches 368 KB of index for every reader who never searches, and it puts other sheets' words inside a sheet. One page, linked from every footer.

What the index does with quoted text: indexed, marked, never snippet-cropped. This was the real question. A conventional snippet — twenty words either side, an ellipsis at each end, no maker — is a fine convention on a page of prose and a machine for producing the tightened source when pointed at eighty-two mounted quotations. It would have manufactured the exact artefact ATTRIBUTIONS.md exists to prevent, once per result, at scale, for the rest of the site's life. So blockquotes are whole records rendered entire with maker and citation, and short quotations inside our prose keep their character ranges so the crop widens around them. The rejected middle option was "crop like any prose"; the rejected safe option was "index our own words only", which would have made Miranda, Fr269 and every line of Dickinson unsearchable on a site that is largely about them.

How the register ranks: a separate, secondary group. /changelog is 25,359 words, 28% of the site. Flat-ranked it buries the sheets on any query naming a writer; excluded, every correction becomes unfindable by word. Its entries come under their own heading below the sheets. This is the register's own front-matter/back-matter distinction, applied to it.

Consequences that were not obvious going in, each of which is now a rule in CLAUDE.md:

Rejected: a hosted search service. Never seriously on the table. The site makes no third-party request and /privacy is gated on it.

Rejected: putting it in queering.js. Its boundary is that it may derive navigation from the DOM and may never create words. A result is a sentence from another page put onto this one. The boundary was worth more than the convenience, so the code is a third file loaded by one page — and it still writes no label: every word is authored in search.html as a <template> and cloned, the way the register's index clones an entry's own chip.

Open: nothing about ranking has been tuned against real use. Weights are heading 8, entry name 8, page title 6, quotation source 2, prose and quotation text 1, with every term required to appear. That is a guess that reads well on the queries we tried. It is worth revisiting when there is any evidence, and there is no analytics here to produce any.

The shared assets are not fingerprinted, and the cache is bounded instead (2026-09-09) Link to this section

The spec's cache-control item gives one clean answer — max-age=31536000, immutable — and it is available only to URLs carrying a content hash. queering.css and queering.js carry their own names, because there is no build step, so the clean answer is off the table and what is left is a choice between two imperfect ones.

Not fingerprinting. The machinery would be a generator that renames both files by content hash and rewrites the reference in all twelve pages, plus a gate to catch a page pointing at a hash that no longer exists. Every commit touching the stylesheet would then churn twelve HTML files, which makes the diff of a one-line palette fix unreadable — and the register depends on those diffs being legible. The prize is 31 KB over the wire, brotli'd. That is not a trade worth making at this size, and it can be made later without undoing anything: adding fingerprints is a strictly additive change to a tool that does not exist yet.

So the cache is bounded instead: five minutes. Chosen for the shape of a visit rather than the size of the file. A reader moving through several sheets in one sitting revalidates once instead of once per sheet, and a bad stylesheet reaches everyone within five minutes rather than being stuck in caches with no way to bust it. That bound is the whole point. This site's characteristic failure is a palette or print change that breaks pages silently — Star Stuff shipped 44 of 46 pages that printed blank — so an unbustable stylesheet is a worse exposure here than a slow one.

stale-while-revalidate is deliberately not on those two, though it is on the plates. The HTML is must-revalidate and therefore always fresh; a stylesheet one visit behind it would render a change that adds a class and its rule together as an unstyled page for that visit. Staleness is only safe where the stale copy cannot disagree with the fresh HTML.

And the plates get thirty days without immutable. Their bodies will almost certainly never change: annales-lugduno-batavi-1863-tab4-gonystylus-miquelianus.jpg names one plate in one volume, and tab 4 of the 1863 Annales is not going to be re-cut. But almost certainly is not what immutable means. It tells a browser the body can never change, on a filename a better scan could overwrite, and asserting a fact we cannot enforce is the same failure as a gold seam on a sheet nobody corrected. Thirty days is a claim we can keep. If a plate is ever rescanned, the honest move is a new filename — but nothing forces that, which is exactly why the promise is not made.

Amended the same day, after the five minutes fired. The accession stamp shipped, and a reader holding the previous stylesheet got the new markup with none of its rules — a paragraph of three unstyled spans where an oval should have been. The paragraph above predicted that event in those words and priced it as acceptable. It is not, and the entry's own reasoning is what overturns it: if this site's characteristic failure is a change that breaks pages silently, then a five-minute window in which every reader sees exactly that is the wrong bound, not a safe one.

What was missing was a third option, not a better answer to the two. The choice above is posed as fingerprinting versus a bounded cache, and both refusals still stand — fingerprinting would churn twelve HTML files per CSS edit and cost the register its legible diffs. But max-age=0, must-revalidate on the two shared assets, the same policy the HTML already has, was never weighed. It needs no generator, no rewritten pages and no gate, so it costs nothing the refusal above was protecting, and it closes the skew to zero rather than to five minutes. It is also more bustable than 300 seconds, which was the stated priority.

The cost is the one thing the five minutes bought: a reader moving through several sheets revalidates once per sheet instead of once per sitting. That is a conditional request returning 304 with an empty body, issued alongside the revalidation the HTML is already doing. Measured against the deployed site on the day of the amendment: the conditional request comes back 304 with a zero-byte body in 0.23s, against 33 KB brotli'd for the full response. Correctness is worth the round trip. (The 31 KB above was accurate when the entry was written and the stylesheet has grown since — it is left as it stood.)

No stale-if-error on those two, and the mechanical reason has a matching one. RFC 9111 forbids serving a stale must-revalidate response, so the pairing cancels. It would also buy nothing: the HTML is must-revalidate and fails closed, so when the origin is unreachable there is no document for a held-back stylesheet to apply itself to. They fail exactly when the page they belong to fails, which is what makes matching the HTML coherent rather than merely consistent.

search-index.json had the same defect and takes a different fix. It was max-age=600, and it is derived from the sheets — so it is precisely the case this entry's own rule excludes, staleness where the stale copy can disagree with the fresh HTML. After a prose edit it could hand a searcher a snippet quoting a sentence no longer on the page it cites, which on this site is the failure that matters most. It is now max-age=0 without must-revalidate, which is not an oversight: zero removes the skew, and leaving the stricter directive off is what keeps stale-if-error legal. That resilience is worth having here and not on the stylesheet, because the index is fetched after the page has rendered, by a reader who has typed something. The document exists either way, so a finding aid a few minutes behind genuinely is better than one that fails closed — the judgement the original note made, and it survives. queering-search.js clones templates authored in search.html, so it is skewable against the markup the way the stylesheet is and follows it.

Revisit when either file is fingerprinted for another reason, or when a conditional request per sheet is measurably costing something.

Sheet No. 8 is a wall, which is a third kind of sheet (2026-09-09) Link to this section

Ryan asked for a zine wall, pointing at Stimpunks' zine walls and at the Fraunces specimen site. One thing in the format does not transfer and it decided the whole design.

A Stimpunks zine wall works by unattributed declaration. Its own page calls it "a wall of declarations", and the pull quotes on Learning at the Edges are deliberately set apart with no source. That is right for a manifesto and is the one move this site cannot make, because here the citation is the product. So a wall here is one of two things and mixing them is the failure: our own declarations, which are ours and need no source, or a chorus of labelled slips. We built the second, because the herbarium already invented it — a sheet that has been in a cabinet long enough carries a stack of determination slips in different hands, every one signed.

So "a wall" joins "a reading" and "an essay" as a sheet kind. The distinction is not decoration: a reading has an order and arrives somewhere; a wall has a chorus, and its argument is made by accumulation. The subject has to deserve that — Monotropa uniflora does, because seven people across 273 years looked at one specimen and each saw something the others could not.

No new visual language. .qe-wall, .qe-slip, .qe-drift and .qe-cutup were built for Sheet No. 4 and are reused unchanged. Wabi-sabi adds one rule the Stimpunks walls do not need: the wall must not be uniform. Twelve slips at twelve angles on an even grid is a pattern, not a paste-up, so sizes and weights differ because the sources differ — a Latin binomial does not get what a letter gets, and neither gets what a poem gets.

Which principles bore on it. Fukinsei is the whole device. Kanso kept the biology off the sheet. Yūgen is why the wall is open at first paint and nothing reveals on scroll. Koko is in the specimen rather than the styling: the plant is pale, ephemeral, lives on decay, and blackens when touched.

The shelf division did real work here. Star Stuff already has the mechanism — its Symbioses field guide entry Nourished in the Dark covers myco-heterotrophy, no chlorophyll, carbon taken and none given back. That is a wrong-fact risk and theirs. Ours is the naming, the letter, the poem's edition history, the editor, and the word. The sheet links across rather than re-explaining, and the label carries a Biology row saying where it went. This is the first sheet where the two sites explicitly divide one subject.

The drawing is the first on this site with no leaf in it, and that absence is the argument: every other panel here is green because every other specimen photosynthesises. The bells and bracts are --qe-flesh, the token written for "the pale flesh of a specimen — a mushroom's stipe, a cut stem", which turned out to have been waiting for this plant. Two drafts were thrown away against the documented drawing rules: the first put the pipes standing on a single long thread, which is the baseline rule 1 forbids, and the second drew the stems nearly upright so the bells sat on top — which loses the one turn the genus is named for. The threads now cross at opposing pitches and the crowns are offset hard sideways.

No plate, and the sheet says so. Every mounted image here is public domain, and there is no public-domain Monotropa uniflora print in hand. The Dickinson manuscript is licensed, modern photographs are in copyright, and Todd's painted panel — the object at the centre of the letter — could not be cleared. Same treatment as the wrong violet on Sheet No. 7: the gap is named on the page and a reader is asked for a better plate.

Star Stuff's field guides have no per-entry addresses (2026-09-09, open, theirs) Link to this section

Noticed while linking Sheet No. 8 across to the Symbioses guide. The SKS mirror of that page carries a convenience link of the form symbioses-field-guide.html#monotropa, and that anchor does not exist on the served page — the whole document has exactly one id, #grid, and the twelve entries are rendered into it client-side from data.

So our sheet links to the page rather than to the entry, which is correct but coarser than we wanted. It is also the situation CLAUDE.md already warns about in the other direction: "If a page ever renders content client-side, the mirror will need a published extraction index." Over there it means a reader cannot be sent to one partnership, and a citation cannot address one either.

Not ours to fix — starstuff.earth is a separate repo. Recorded here so that a session in that repo has the finding, and so the next Queering Earth sheet that wants to cite one field guide entry knows it cannot yet. Worth adding: their page already links to Helen Edgar's Monotropa essay, so both sites arrived at it independently, and the cross-link now runs both ways.

The social-card report enumerated a hand-kept list (2026-09-09) Link to this section

make-images.py generated the new card correctly and did not report it, because its closing summary iterated a hardcoded tuple of filenames that nobody had added a line to. Caught by eye, not by a guard.

Harmless in that direction and not in the other: the same hand-kept list would report a complete-looking run while a card had silently failed to generate, which is precisely the class of failure this repo keeps building checks for. The report now enumerates what og_card actually wrote and prints a count, so a new card reports itself and a missing one is visible.

Also added: a ghost_pipes sprig, because the generic one draws leaves in lichen and heads in three accents. On the one sheet whose entire argument is a plant with no chlorophyll and no foliage, the stock card was arguing with the page — the same fault as a legend that no longer matches its own drawing.

The register is indexed by sheet, and the association is authored (2026-09-09) Link to this section

The open item from the contents work, closed the same day. /changelog is written by accession, which is by date, because a sheet, its corrections and the CSS it needed are one dated event. That is the right unit to write in and the wrong one to look something up in: a reader is usually asking what happened to one sheet, and its entries are scattered across sixteen dates.

The distinction the first attempt missed: a contents list is front matter, an index is back matter. That is why a table of contents measured so badly here (1,293px at the top, delaying the first entry by three and a half screens) and why an index does not: it sits at the foot of the page, where a bound volume has always kept one, and delays nobody. One line up by the legend points down at it. The register's own first accession is back to 1,839px from the top.

Which sheet an entry concerns is stated in the markup, never inferred. Each .qe-entry carries data-sheet. Deriving it from the links inside an entry was considered and fails on the evidence: the Dickinson accession links /on-being-ill, /promises-like-pie-crust and /wild-nights and concerns only the last, so incidental cross-references would file corrections under sheets they have nothing to do with. On a site whose whole risk is a wrong attribution, an index that silently misfiles a correction is the worst bug available, so the association is authored — 73 entries, read one at a time — and guarded.

Two entries legitimately belong to two sheets and carry both tokens, which is why the field is a token list rather than a single value: the byline rule changed Sheet No. 4 and gave No. 1 a second reader in one stroke, and today's correction about the seven principles touched the colophon and this register together. 73 entries file as 75 index lines.

What is authored and what is derived. Every group, its heading, its sheet number, and the order the groups appear in are written in changelog.html — those are editorial words, and queering.js may not write words. The script only files: it clones an entry's existing name and its existing kind chip and puts them under the group the entry declares. Nothing is composed, summarised or truncated, so the index cannot end up calling an entry something the entry does not call itself. The group labels were checked against each sheet's own <h1> and against the plate's cards rather than typed from memory.

A guard, because the failure is silent. A typo'd slug does not throw and does not show: the entry matches no group, drops out of the index, and the register above it still reads perfectly. check-markup.mjs now validates every data-sheet token against the pages that exist (plus the literal the-site), reports an empty declaration, and reports a group that nothing files into — which catches the same typo from the other end. Made to fail before it was believed, per the standing rule: a typo'd entry slug, an emptied declaration, and a stale group each reported with a line number and exit 1; then reverted and the clean tree re-run.

One layout attempt discarded on measurement. The index items were first a wrapping flex line, chip beside name. A chip plus an entry name exceeds the measure almost every time, so every single item put its chip alone on a row above itself and the index came to 6,726px for no extra information. Ordinary inline flow — chip opening the line, name wrapping beneath — is 5,502px and is what an index entry has always looked like anyway.

The one redundancy left in. A sheet's Mounted entry is named after the sheet, so it restates the group heading directly beneath it. Fixing that would mean rewriting entry names in the register, which is editing the record to suit an index built on top of it. The index defers to the record.

Contents on the long sheets: derived list, authored addresses (2026-09-09) Link to this section

Ryan wanted to see what is coming on a long sheet, jump around it, and share deep links to headings. Three axes were on the table from NN/g's guide: rail vs body, sticky vs nonsticky, top vs in-body.

The three are really two. NN/g couples the first two — "If the table of contents is…in a left or right rail…then the table of contents should be…sticky. In the main body…nonsticky." So the choice is rail-or-body and sticky follows. Top it calls the "safe choice".

Body, nonsticky, straight after the lede. A rail would fill the margins either side of the 34rem measure, and those margins are the negative space the spacing work had just spent an accession clearing. Sticky also eats viewport height at 400% zoom, which is a WCAG 1.4.10 problem this site does not need to invent. NN/g's own testing adds that "many users failed to notice the sticky table of contents" on mobile. Placed after the lede rather than before it, so the sheet's opening sentence still comes first.

Which principles actually bear, and which do not. Kanso and seijaku are genuinely against a rail: permanent furniture, and furniture that never leaves the screen. Yūgen gives one hard rule — open at first paint, never an accordion, which is the register's existing "a ledger you have to open is a ledger nobody reads". And fukinsei mildly favours a rail, since an off-centre two-column composition is more asymmetric than a centred one; it was overridden rather than pretended into agreement. Koko and shizen are neutral here. Stacking all seven onto one side would have been the tightening this site keeps logging.

The two decisions that mattered more, and NN/g covers neither.

1. The list is derived from the DOM, never typed. A hand-kept contents list is a second copy of every heading, and this repo's oldest rule is that two copies drift and the accessible one rots. With no build step that leaves client generation, and three good things fall out: it is not content (every heading is fully server-rendered; the script only reflects them), the served HTML carries no list so the SKS mirror never indexes a heading twice, and losing the script loses a shortcut and no words.

That last point is also why this may live inside <main> when .qe-elsewhere may not. The outside-<main> rule exists to stop one sheet's navigation being indexed as another sheet's content — a cross-page contamination. A self-referential list of this page's own headings cannot cause it, and since the list is never in the served HTML the question is moot anyway.

2. The ids are authored, not slugified. This is the half that breaks quietly. An id derived from heading text dies the moment anybody rewords the heading, and every link a reader shared dies with it. So each <h2> carries a short topical id stated in the markup — #eden, #the-colon, #quetelet, #wabi-sabi — the way --rot is a fact about a slip. The permanent thing is authored, the derived thing is computed, and nothing is written twice. check-markup.mjs already guards duplicate ids, so the guard for this existed before the feature did.

The section mark, and the trade it takes. A § beside each heading, linking to it. Always visible rather than revealed on hover, because hover hands the affordance to mouse users and to nobody else — no keyboard, no touch. The glyph is drawn with an empty alt string (the chain-arrow device) and the link is named by a visually hidden span, so it announces as "Link to this section". That does append four words to every heading's accessible name, which is the accepted cost and is what MDN and GitHub do; the alternative is the affordance not existing for most people. A real space before the <a> in the markup is load-bearing: without it the name computes as "…the windsLink to this section", because CSS margin is not whitespace. Found by reading the accessibility tree, not by looking at the page.

No scroll-spy. NN/g says highlighting the current section helps. It also means a scroll listener, a mark that moves, and a second thing on screen that never settles — against the register's standing "no new motion". :target marks where a reader landed, which is the case a shared link actually creates, and it is drawn in the gutter with absolute positioning so arriving at a heading does not shift it: a border-left plus padding would move the words sideways at the end of a smooth scroll, the one moment a reader is looking straight at them.

Not on /changelog, and this is the decision worth keeping. The register is the longest page on the site (16,052 words) and looked like the strongest case. Built and measured, it was the worst: its labels average 148 characters against 22–34 on a sheet, so the block came out 1,293px against 319–510px everywhere else, and it pushed the first accession three and a half screens down. The cause is not a bug — a register's accession headline is a sentence, which is that component's own written design decision.

Both ways to shrink it were forbidden. Truncating a label is this site's characteristic failure applied to itself. A short second label beside each heading is the drift. So the register keeps its section marks and its sixteen addresses — deep links there work, which was half of what was asked — and has no contents list. Removed after measuring rather than shipped because it had been built.

The register wanted an index by sheet, not a contents list — built the same day. What a reader of /changelog wants is usually "what happened to sheet X", and the accessions are grouped by date. See the entry below; the short version is that a contents list is front matter and an index is back matter, and reaching for the first when the page wanted the second is what produced the 1,293px block.

A wrinkle flagged and deliberately not solved. On the sheets the headings are often quotations, so the Tempest's contents reads Assembled, not born · A household of three · O, I have suffered with those that I saw suffer · Abhorred slave · O, brave new world. That is lovely and it is not scannable, which is NN/g's whole purpose for the thing. The fix is not a second short label — it is better headings, and rewriting headings on shipped sheets is an editorial call rather than a design one. Named here so it is a choice rather than an oversight.

One rule amended rather than smuggled past. CLAUDE.md said queering.js was "the two view controls, and nothing else". This breaks that, so the rule became a boundary instead of a tally: it may derive navigation from the DOM; it may never create words. A count of features is a rule that gets quietly broken the first time a third thing is worth having.

Three surfaces, a spacing scale, and patina as a record (2026-09-09) Link to this section

Prompted by Ryan reading on wabi-sabi in web design and asking how this site scores against the seven aesthetic principles that literature names. Six of the seven were already here; two — fukinsei (asymmetry) and datsuzoku (freedom from convention) — more thoroughly than the sources state them. Four decisions came out of the exercise.

One sourcing note first, because it shaped everything after it. The list circulating as "the seven principles of wabi-sabi" is Hisamatsu Shin'ichi's seven characteristics of Zen art, from Zen and the Fine Arts (Kodansha International, 1971). Zen aesthetics and wabi-sabi overlap and are not the same thing, so the relabelling happened in transmission. The third of the seven — the one about age — is where the transmission frays, and the design advice glosses it with no age in it at all, which is why "patina" recurs in that literature without ever resolving into a principle. This accession is mostly about that hole.

Corrected the same day — the first version of this paragraph overclaimed. It stated flatly that the popular list names shibui where Hisamatsu names koko, and that the swap is what dropped the aging. That is not established. At least one rendering of Hisamatsu's seven gives shibui/shibumi for that characteristic itself, glossed "lofty dryness" — the same sense the koko renderings carry. The confident version was written from memory before anything was checked, and the instruction two sentences later to verify against Hisamatsu before any of this reaches public copy is what caught it, when the colophon section was written and the checking actually happened. The paragraph above is the part that survives verification, because it is a claim about two texts a reader can open rather than a ruling on Hisamatsu's vocabulary. Full working, with the citation pinned from Crossref, is in ATTRIBUTIONS.md; the register entry is corrected too.

We use koko as the term for the weathered principle, on the warrant of the peer-reviewed paper we have the seven from, and the colophon says the renderings disagree and that we cannot settle it from here. We have read neither Hisamatsu nor Koren, and the page says so rather than implying a lineage.

1. A panel picks one of three surfaces: bare, ruled, ruled off. --qe-card appeared fifteen times in queering.css, thirteen of them with the same 1px rule and 2px radius, so a specimen, our own commentary, and a housekeeping note were indistinguishable by surface. That is a hierarchy defect and not an aesthetic one. .qe-restaged went bare, .qe-untidy and .qe-register-note went ruled off, and ruled now means "somebody handed this to us."

The third tier is hairlines and not a recessed tint, and that is the interesting part. A --qe-paper-deep fill was the obvious answer and was tried first. In daylight it drops --qe-moss to 6.90:1 and --qe-rust to 6.21:1 — under the house 7:1, over WCAG AA, and therefore passed check-contrast.mjs clean. This is the open item logged the day before (the guard gates at AA, the 7:1 target is held by hand-chosen tokens and nothing else) arriving as a real near-miss. It closed the same day: the gate was raised to 7:1 in two tiers, and the site passed it without a colour changing. See that entry below.

A second thing the guard cannot see turned up in the same pass: a ::marker is not an element with text, so nothing measures it. Dropping .qe-untidy's fill took its bullets from 4.17:1 to 3.89:1, and checking the neighbours found the register's own entry bullets drawn in each kind's accent — 2.15:1 for lichen, 2.40:1 for marigold on paper. Both fixed by the rule the stylesheet already states five times over: the colour goes on the rule and never on the glyph. Markers took --qe-moss at 7.80:1.

2. Space is a scale. Twenty-five distinct margin values shipped. The argument is not tidiness — it is that asymmetry only reads as asymmetry against a norm, and this site's entire typographic case is deviation. Twenty-five arbitrary gaps read as noise and flatten the deviations that were authored. --qe-space-* is quarter-lines of the 1.96rem body line; the page was already close by ear, so quantizing moved most gaps by one to three pixels. Paragraph spacing went 1.35rem → 1.47rem, the one deliberate loosening. The scale governs space between blocks only.

Three corner profiles for the same reason, none square and no two alike: a sheet handled a hundred times does not have four identical corners. It is a radius, so it is free in both contrast and print. Koko for the price of a token.

3. Patina is a record, not a texture — .qe-provenance. The register had already logged a correction or a re-determination for every one of the seven sheets, and no sheet said so on its own face. The foot of each sheet now carries its mounting date and its correction counts, each clause linked to the entry here that did it. Inside <main>, so the mirror has it. It is true, checkable, accrues on its own, and survives plain view, paper, a screen reader and 400% zoom, because it is a sentence.

Every alternative on the table was a picture of age drawn over the words. The research recommends a noise tile and filter: blur(0.5px) contrast(1.1); both refused. Texture never goes under text, and the reason is the one above: a grain varies effective background luminance per pixel, and the guard composites computed colour pairs. Grain under body text would pass every check here.

What was taken from the texture advice: the wash is no longer position: fixed — the stains held still while the paper scrolled past them — and its four positions are now --qe-fox-* tokens stated per page, because all nine sheets were foxed in identically the same four places. Same idiom as --rot on a slip: a stain is a fact about one sheet.

The wash does not tile, and one draft that did shipped a visible line. It was tiled at a 150rem period so that a long sheet would not have clean paper through the middle, with a note claiming a reader would never meet the repeat. Ryan met it on the first sheet he looked at. The cause is arithmetic: transparent 70% puts a gradient's edge at 0.7 of its radius, so in a 2400px tile a stain at 8% reaches 278px above the tile's top and one at 96% reaches 352px past its bottom, both cut off square — and a cut-off gradient meets the next copy of itself as a step, which no softening repairs. Keeping the tile would have meant constraining every future page's stain positions to a safe band inside it, which is a trap for whoever writes the next sheet, bought in exchange for an even cast on the two pages long enough to want one. Four stains over the whole sheet instead. A long sheet is sparsely foxed; spots do not multiply to fill a bigger sheet.

4. The gold goes on the mend. Kintsugi is not that the crack shows; it is that the most precious material in the workshop is spent on the break. Read that way the register's taxonomy was backwards — --qe-marigold marked Mounted, the routine intake. Two tokens swapped: Mounted takes --qe-lichen, Re-determined takes --qe-marigold (the largest correction a register records — the specimen turned out to be a different thing), Label corrected keeps --qe-coral. .qe-correction's left rule became marigold and gained a gold seam through the joint rather than down the edge, with coral kept on the strike: the strike is the break, the join is the mend. The unclassed default became --qe-rule rather than an accent, so a mistyped class reads as plain. --qe-verdigris leaves the register.

The masthead vine on /changelog is the legend — four blooms in the four kinds' colours in legend order — so its second and third flowers changed with the tokens. A legend that no longer matches what it explains is worse than no legend.

The constraint that makes this honest: a seam requires a repair that is actually in the register. No rule derives --mended; the class is written on a sheet whose entries exist. A gold join on an uncorrected sheet is decoration asserting a fact — the same failure as an image of text — and it would make the real mends unfindable. All seven sheets carry the seam today, so it currently distinguishes nothing; that is a fact about this site rather than a fault in the device, and Sheet No. 8 will arrive clean.

What was considered and not done. A deckle edge via border-image (a picture of an edge, and it fights the print sheet). Per-corner foxing spots on card edges (texture, one step from the thing refused above). Deliberately mis-set opsz on small caps to imitate a rephotographed plate (too subtle to be worth a token, and it fights font-optical-sizing: auto). Varying the gap between register accessions to imitate uneven intake (fights the scale it was just given, and the register's flatness is the ledger being a ledger).

Addresses on this site are extensionless (2026-09-07) Link to this section

https://queering.earth/on-being-ill, not /on-being-ill.html. The file on disk is still on-being-ill.html — only the address changed.

Why the question came up. Netlify's Pretty URLs post-processing is on by default and rewrites internal links to strip .html, so the served page said href='/coming-to-terms' while the repo said href="coming-to-terms.html" and every canonical tag and sitemap entry said .html. The site linked to one address and declared a different one canonical. Found by reading the served page rather than the repo, while checking that the sibling nav had deployed.

Two ways out were on the table: turn the setting off, or adopt what it produces. Ryan chose to adopt it. So canonical tags, og:url, sitemap.xml, and every internal link now say the extensionless form, and the repo describes what Netlify actually serves. Nothing is rewritten on the way out any more, because there is nothing left to strip.

What this costs. The filename and the address no longer match, which the "every page is a file at its own path" line in CLAUDE.md used to be able to claim literally. That line now says so explicitly rather than leaving the next session to discover it.

tools/check-sitemap.mjs enforces it. A <loc> carrying .html now fails instead of passing quietly by resolving to a real file — verified by putting one back and watching it fail. tools/serve.mjs needed no change: it already retried <path>.html for clean URLs, with a comment saying why.

Still true, and fine: /on-being-ill.html also answers 200. Nothing links to it and its canonical points away, so it is an unlinked alias rather than a competing address. Forcing it to 301 would take one _redirects line per sheet, which is a per-sheet chore forever; not worth it unless the alias starts showing up somewhere it matters.

Until now a sheet's only internal link was /. A reader arriving on the Woolf sheet from a search result had exactly one way onward: back to the plate. Each sheet now ends with Elsewhere on the plate, carrying the other sheets as the plate's own cards.

Two decisions inside that, both of which would be easy to get wrong later.

It sits outside <main>. Not tidiness — the SKS mirror takes page content from the <main> landmark and nowhere else, deliberately, so that navigation furniture is not indexed as content. A sibling card inside main would index "Coming to Terms" as part of the Woolf sheet, in the mirror and in anything built on it. tools/check-markup.mjs cannot catch this: the markup is valid and the landmark is correct. The comment in the markup says so at the point where somebody would move it.

The sibling cards carry kind, number, and title — no description. The plate is the record; these are a reference to it. With two sheets that reads as restraint. At ten it is the whole point: repeating each card's description on every other sheet is ninety copies of a sentence free to drift from the one on the plate, which is the two copies drift failure the plain-view rule exists to prevent, wearing a different hat. Titles duplicate, and a title is already repeated in the target's <title> and <h1>, so it is the one string the site cannot avoid holding twice.

auto-fill, not auto-fit. With a single sibling, auto-fit collapses the empty track and stretches one card across the whole measure, which reads as a banner. auto-fill keeps the track and the card keeps its size. The plate itself stays auto-fit, because there two cards should fill the width.

What this does not do is give each sheet its own mark. That was the other reading of the suggestion that started this, and it is deferred: a per-sheet emblem is ornament until a reader needs to tell sheets apart at a glance rather than by reading the title, which is five or six sheets away. Every mark is then a hand-drawn asset forever, so it should be earned first.

The plate uses Star Stuff's card class names, on purpose (2026-09-07) Link to this section

index.html now mounts the sheets as numbered cards. The box is <div class="card-wrap"> and the link is <a class="card"> — Star Stuff's names, deliberately adopted, which reverses this repo's standing default of not importing its habits.

The reason is narrow and it is the same test CLAUDE.md sets for porting a check: the failure became possible here. tools/check-markup.mjs already carries a card-wrap rule — it came over with the file — and until this commit it could not fire, because there were no cards. It guards the failure that shipped twice on Star Stuff: a new wrap opened before the previous one closed, so the second card renders inside the first card's box, sharing one border. Valid markup, invisible to every other check.

Writing our own class names would have produced a lookalike the guard cannot see, and the guard is div-and-class-specific by design. Verified live rather than assumed: nesting the second wrap made check-markup fail with both the nested-wrap message and an unclosed-wrap message, and restoring it went quiet. A check nobody has seen fail is a check nobody trusts.

Two smaller things settled with it:

The masthead credits Nick Walker for the phrase (2026-09-07) Link to this section

Our tagline is "Post-normal possibilities." Walker's book is Neuroqueer Heresies: Notes on the Neurodiversity Paradigm, Autistic Empowerment, and Postnormal Possibilities. One hyphen apart, on a site that quotes him on its home page, about the subject of his book. Found while building the Coming to Terms sheet, in our own glossary entry for neuroqueer, and verified against neuroqueer.com.

Ryan's call: credit him, on the masthead. It read after Nick Walker, linked to the book, with the full explanation in Queering is a verb where Walker already appears.

Why crediting was the right of the three options. Helen may well have arrived at the phrase herself — she wrote it in the founding brainstorm — and post-normal has a genuine separate lineage in post-normal science, coined by Silvio Funtowicz and Jerome Ravetz in "Science for the post-normal age," Futures, September 1993 (checked 2026-09-07, so the file no longer carries that as an unverified aside). None of that makes the collision invisible. The page therefore says the true and generous thing — he published it first — and claims nothing about the route the phrase took to get here.

The wording on the page is deliberately "after." Not "his phrase," which would take the coinage away from Helen, and not silence, which was the option that stayed defensible only until somebody noticed the subtitle. After is the form poetry uses for exactly this, and it is the only one of the three that is true no matter which way the origin actually ran.

This settles the attribution question and not the wording of the tagline itself, which stays open above as Helen's and Ryan's.

Re-determined 2026-09-13, on Ryan's word: the masthead line comes off; the credit does not. Ryan's call: credit him, on the masthead was half right and stays half right. Crediting was the right call of the three. The masthead was the wrong place to do it, and it took six days and three readers to find out — the same three words read as a death notice, as an endorsement, and as a statement that this site is built on one person's theory. Nobody misread the paragraph under Queering is a verb, which has said all of it since the same day and says it with room.

The transferable rule: a credit that needs a sentence must not be set as a label. The masthead had room for three words, so three words is what it got, and every reader supplied the rest themselves — differently. That is the paraphrase failure this file already records about the working tagline, arriving from the other end: a form too small for the claim will shorten the claim, and the shortened claim is not a quieter version of the true one. The house's own test applies to our own credits, not only to other people's words: if we changed the words, they are ours — and three words that assert an endorsement nobody gave are ours in the worst way.

A sheet is a reading or an essay, and the label flexes (2026-09-07) Link to this section

The model settled below assumed the specimen is somebody else's — Woolf's essay, a painting, a word. Coming to Terms is Ryan's own essay, so there is no external specimen to mount, and the question is whether that needs a second page type.

It does not. It needs the label to flex, which a description list does for free:

a readingan essay
Specimen, Maker, This textWritten by, Written, First published
Read / Read byThis text / Terms

The kicker above the title says which — "Sheet · a reading" or "Sheet · an essay" — and that is the whole distinction. Both are sheets, both carry a label, both keep our words and other people's visibly apart. On an essay the specimen is simply the terms it is about, which for a herbarium site is the right shape anyway: a word collected, pressed, and compared against others until one of them fits.

One rule the essay case adds. When a sheet reprints something published elsewhere, the label says what was changed. Coming to Terms drops the block quotations from other writers that the original carries, so its label says so and says the author's own words are unchanged. An unmarked edit of our own published text is the same failure as an unmarked edit of somebody else's — the site just happens to be the injured party.

What Queering Earth is for: a reading becomes an artifact (2026-09-07) Link to this section

More Realms is where Helen thinks in prose. Queering Earth is where a reading becomes an artifact — the sheet interprets its own subject, which is the one thing a WordPress template structurally cannot do and a hand-built page can.

Ryan's call, and explicitly provisional: at least to start, and we are not sure of the shape yet. Recorded because it unblocks the second sheet, not because it is final. If it turns out that the artifact-making is not what distinguishes the two sites, this is the entry to come back and overturn.

The label carries a byline, and the byline names who read it (2026-09-07) Link to this section

Helen's voice and Ryan's voice, individually, and occasionally both. So the byline is per-sheet and it is a name, not an institution — "Helen Edgar," "Ryan Boren," or both, on the label of the sheet they read.

This is the house voice's rule applied in the type rather than in a policy: name whose "we" you are centering. It also means a sheet may be written in the first person singular, which Star Stuff never is, and that difference is a feature of this site rather than a lapse.

The label carries dates — starting with the date of the reading (2026-09-07) Link to this section

Undecided in principle, decided in practice: start with the date in the label. A date is one line to add now and a guess to retrofit later, so the cheap direction is to have it.

A site about re-reading should show that a reading happened on a day, and that another day would have produced a different one. What the label does about the original's date when a work was revised is a separate and now-open question — see above.

The content model: a sheet mounts a specimen and carries our label (2026-09-07) Link to this section

A piece is a sheet. The specimen is what it mounts. The label is what we say.

The herbarium distinction is load-bearing, not decorative. The specimen is the thing collected and it is somebody else's — Woolf's essay, Brontë's novel, the Rothko, the word. The sheet is our page. The label is the small block of type where we speak, and it is explicitly ours: subject, maker, date of the original, date of the reading, and who read it. Everything below the label is free, because the sheet interprets its own subject — the design intent Helen actually named in the brainstorm, and the reason a template was never going to hold this site.

That split also does the attribution work ATTRIBUTIONS.md exists to force. Their words sit in the specimen. Ours sit on the label. The line between the two is drawn in the layout instead of being left to a reader's good faith.

Concretely: flat paths at the repo root, on-being-ill.html, no prefix and no type suffix. The index is a plate — cards laid out like a Victorian specimen sheet, which is already the home page's visual language. .qe-specimen and .qe-specimen-label are in queering.css today, screen and print rules both, so the vocabulary and the stylesheet are the same argument.

No collections yet, and the trigger is named. Helen already writes in sequences — the Re-worlding Neurodiversity / When the Ecology Fractures / Autistic Burnout Recovery run is Parts 1 through 3 — but she names them afterward, once Part 1 is already published. Declaring a collection at n=1 is a promise on the page that nothing has been written to keep yet, and an unfilled run reads as abandonment rather than as patience.

The trigger: the third sheet that shares a lens. Then a run, and not before.

Note that this is the same trigger as the CMS question above, seen from the other side: a run is the first repeating, uniform content type. When we add one, Sveltia comes up for discussion in the same week. That is not a coincidence to be surprised by later.

Print: no separate print artifact. Star Stuff has nine broadsides because it has 101 zines and an earned print practice. Here the paper version is not a translation of the web page — a herbarium sheet is already a printed object, so the sheet is the native form and the screen is the preview. The @media print block in queering.css is the print form, and tools/check-contrast.mjs measures it. Revisit when there is a specific sheet somebody wants to hand to a person.

What we rejected, and why it is written down. Two other shapes were real candidates.

And Star Stuff's taxonomy was not imported. Zine, field guide, broadside, collection, glimmer wire — 101, 24, 9, 16, and a dated dispatch. That vocabulary was earned across 195 pages. Adopting it here would be inheriting the answers to questions this site has not asked.

One caveat, stated rather than buried. "Specimen" pins things, and mounting a Disabled woman's essay on illness to a card is worth saying out loud. The specimen/label split is what makes it sit right: we are not pinning Woolf, we are mounting her essay and signing our own reading. If it still reads wrong to Helen, reiteration is the fallback noun and the structure survives the swap unchanged — the model is the split, not the word.

Settled pending Helen's read of the noun. The structure is decided. The vocabulary has one open substitution in it.

queering.earth is not registered — build anyway (2026-09-07) Link to this section

whois.nic.earth returns "No Data Found". Registering it is Ryan's, and a purchase. Nothing else waits on it: the site deploys to its .netlify.app hostname and the domain attaches later.

Two things must NOT be switched on until the domain resolves. The host redirect in _redirects would send the only working address to one that does not answer — a site that is simply down. And adding this domain to the SKS mirror's SITES map would fail that sync, because the mirror fetches over the network.

Netlify: continuous deployment from the repo, matching Star Stuff (2026-09-07) Link to this section

Project queering-earth on the Stimpunks team (id 4115815c-5811-4df6-8f6f-9598e85d2d72), wired to Stimpunks/Queering-Earth on main through the same GitHub App installation Star Stuff and Cavendish Cards use. No build command, no publish subdirectory — the repo root is the site, exactly as Star Stuff is configured.

Deploy previews on pull requests are left on, and that is the point rather than a default: it is the review path for anyone editing through the GitHub web editor, and it is the reason the CMS question above can stay deferred. A pull request produces the real page at a real URL before anything reaches main.

.netlify/ is git-ignored — it holds the local link state, not configuration.

Creating the project through the Netlify API does not wire continuous deployment, and nothing you can do from the API fixes it. createSiteInTeam with an installation_id produces correct build settings and a working first deploy — Netlify clones through the GitHub App fine — and then no webhook, no deploy key, and no Netlify-side github_app_checks hooks. Pushes are ignored while the dashboard shows a green light and "Auto publishing is on" above a commit several pushes stale. It looks exactly like success.

Three things were tried and none of them work:

  1. updateSite with the repo block again. Leaves deploy_key_id: None and zero Netlify-side hooks. It does kick a one-off build of current HEAD, which is a trap of its own — that stray deploy looks like the link repairing itself.
  2. A hand-made GitHub webhook pointed at https://api.netlify.com/hooks/github, matching Star Stuff's exactly (JSON, seven events, no secret). GitHub delivers, Netlify answers 204 OK, and builds nothing. Verified twice: a push delivered at 23:29:59 had produced no deploy six minutes later. Netlify only honours a hook it created and recorded on its own side.
  3. Concluding anything from a short poll of netlify api listSiteDeploys. It lags, and it lags by minutes. Give it three before calling a push ignored.

The only fix is netlify init --force in this repo, answering Authorize with GitHub through app.netlify.com, then an empty build command and . as the deploy directory. It provisions the webhook, the deploy key, and the status-check hooks together. It needs a browser OAuth grant, so a human runs it once.

How to tell a wired project from a deaf one — the dashboard will not tell you:

gh api repos/Stimpunks/Queering-Earth/hooks --jq 'length'
netlify api getSite --data '{"site_id":"4115815c-5811-4df6-8f6f-9598e85d2d72"}' \
  | python3 -c 'import sys,json; print(json.load(sys.stdin)["build_settings"]["deploy_key_id"])'

Star Stuff answers 1 and a key id. A 0 and a None mean pushes are going nowhere.

The look: daylight herbarium, not green Star Stuff (2026-09-07) Link to this section

The strongest differentiation from a night-sky site is not the same site in green — it is the other end of the day. Warm vellum ground, dark ink line art, jewel accents, specimens laid out like a Victorian plate. It matches the antiquarian-sticker-book reference Helen named, and it makes the two sites unmistakable at a glance. Recorded as a rule in CLAUDE.md.

Fraunces as the display face (2026-09-07) Link to this section

Fraunces carries a WONK axis — letterforms that deviate from the norm, exposed as a setting. A site about queering normativity setting its masthead with the deviation axis turned up is the argument made in the type. Body face is Newsreader. Both are Google Fonts variable families with real fallback stacks.

Plain view is a class, never a second page (2026-09-07) Link to this section

Helen asked for "a plain access version if doing that." Built as html.plain toggling a stylesheet over one document, with the stored preference applied inline before first paint. The alternative — a decorated page and a separate accessible page — drifts, and the accessible copy is always the one that rots.

Three guard scripts ported from Star Stuff, five left behind (2026-09-07) Link to this section

check-markup, check-sitemap, and check-contrast came over and pass on index.html. check-classes, check-overlap, check-sheets, check-embeds, and check-card-order did not: they catch failures this site cannot yet have. Port one when its failure becomes possible. A check that cannot fail is a check nobody reads.

serve.mjs roots at the repo, not at process.cwd() (2026-09-07) Link to this section

Star Stuff's copy serves whatever directory it was started from, so a wrong-directory run looks exactly like a site with every page missing. This copy derives its root from the script's own location.

Verse gets a shared component, and every line is its own element (2026-09-08) Link to this section

Added for the Rossetti sheet. .qe-poem lives in queering.css rather than in the page, because poems are going to recur here and the second one would otherwise copy the first one's CSS and then drift from it.

A poem's line breaks are the object being mounted. Reflowed into prose it is a different poem, so the component does three things a <blockquote> would not:

  1. Every line is a <span class="l"> set to display: block. Not a <br>-separated run. Two reasons. A <br> interleaved among spans breaks nth-child counting, so an indent driven by an even/odd rule silently re-indents the whole poem the moment somebody adds or removes a line — the indent is a class the markup states outright instead. And a run broken only by <br> gives a wrapped long line nothing to hang from.
  2. A hanging indent on every line, so that a line too long for the measure is visibly a wrap and can never be mistaken for a line the poet wrote.
  3. .l-in reproduces the source printing's alternating indent. That class is a fact about the 1896 setting and nothing else — see ATTRIBUTIONS.md. It is not a decorative rhythm to apply to any poem.

The type steps down at narrow widths, and this is the one place on the site it may. Seven of Rossetti's twenty-four lines wrapped on a 375px viewport at the body size, and a poem read at that ratio is being read as prose. .qe-poem .qe-stanza drops to 0.98em under 26rem, which fits all twenty-four. It is a relative size, so browser zoom still scales it, and the hanging indent remains as the safety net when a longer poem needs it. Verified: 24 lines, 0 wraps, no horizontal overflow, at 375px and at desktop.

Stanzas get break-inside: avoid on paper. A stanza split across a page break is the one thing this component must not do.

A sheet is titled from a phrase in the specimen (2026-09-08) Link to this section

on-being-ill.html is "The Army of the Upright". promises-like-pie-crust.html is "The Die Uncast". Both titles are lifted from the work being read; both filenames name the work instead. That split is now deliberate and worth keeping: the filename is the address a reader searching for the source will guess, and the title is what the sheet found in it. An essay written by us is titled by us — coming-to-terms.html is "Coming to Terms" — so the convention only applies to a reading.

The header art is Art Nouveau, and it took Helen three notes (2026-09-08) Link to this section

The Rossetti sheet's drawing was rebuilt twice after review, and the reasons are worth keeping because the first version looked fine and was wrong.

v1 — five upright stems, evenly spaced, on one flat baseline. Each plant separate, no shared stem, one colour each: the argument of the sheet drawn literally. Helen: "can we have squiggles and swirly bits so it isn't all linear? may be add some mushrooms or something". She was right, and it was a fault, not a preference. A sheet whose thesis is "counter-narratives following their own rhythms and temporalities" had a drawing in military formation at the top of it. No guard can catch that; the markup was valid and the tokens were correct.

v2 — scattered, coiled, with fungi. Different root heights, fern croziers, tendrils, three mushrooms. Better, still built out of upright stems.

v3 — Art Nouveau, and the real answer. Helen's brief: "ornate swirling botanical style, with flowing curved vines, spiraling tendrils, and organic scrollwork instead of straight or geometric lines… asymmetrical, flowing composition… delicate filigree-like branches winding around… no rigid or angular shapes. Not linear — alive, sprouting in all directions with flow." What that actually required:

  1. No baseline and no roots. One whiplash vine enters at the lower left and sweeps up across the panel; everything else hangs off it. There is no ground to stand on, so nothing can line up.
  2. Every terminal curls. Vines, tendrils and scrolls all end in a spiral turning back on itself. A curve that merely stops is the thing this drawing is not.
  3. The shapes had to change too, and this is the part that nearly got missed. The flowing linework landed in v3 while the flowers and mushrooms were still v1's — six-ellipse daisies and flat domes on sticks with one horizontal rule for gills. Against sinuous vines they read worse than they had against straight stems, because now they were the only rigid things on the panel. Blooms are five sinuous petals at uneven spacings; caps have an undulating margin over a tapering bent stipe; .gills was deleted outright. A style note about line is also a style note about form.
  4. A taller canvas. 560×260, up from 434×156. Filigree needs vertical room or the curls close into blobs.

The motion model needed no change and got better. Every vine, tendril and volute is a .stem, so it draws itself on, and a long S-curve unrolling is what that animation was always for — v1's short uprights were the hard case, not this. Leaves, blooms, fungi and moths are .sprout groups. Verified after the rebuild: 16 stems, 28 sprouts, plain view shows the complete drawing with nothing hidden and no dash offsets, and the only opacity: 0 in the stylesheet is inside @keyframes qe-unfurl, which reduced motion never runs.

--len is measured, not estimated. Each path's --len is its real getTotalLength(), read out of the live DOM and written back. A declared length shorter than the actual one turns the dash into a repeating pattern and the vine draws on with gaps in it — three paths were short on the first pass and it is invisible in the finished state, only in the animation. If you edit a d, re-measure that path.

Landscape plates wanted .qe-plate-wide, and then did not (2026-09-08) Link to this section

Added and removed the same day, and worth recording because the next landscape plate will want it back. .qe-plate caps at 23rem, which is right for a portrait plate and useless for a landscape one: Darwin's Bryonia tendril was 1000px of fine woodcut across 520px of height, and at 350px wide its two counter-turning spirals closed into a smudge. .qe-plate-wide raised the cap to var(--qe-measure) and no further — the reading column stays the limit on this site.

Then the two black-and-white Darwin woodcuts came off the sheet (see below) and it had no users left. A CSS modifier nobody applies is dead code, the same way a guard that cannot fail is a check nobody reads, so it went. If a landscape plate ever lands here again, the rule is one line: .qe-plate-wide { max-width: var(--qe-measure); }.

Colour over subject matter for mounted plates (2026-09-08) Link to this section

The Rossetti sheet first mounted two Darwin tendril woodcuts, chosen because the sheet's argument is about holding on without merging. Ryan: "The black and white tendril illustrations are a little underwhelming. Let's drop the tendril requirement and go for colour." He is right about the page. A herbarium sheet in daylight is a colour object, and two grey rectangles of 1876 line-block sat on it like photocopies — the site's own model was arguing against them, and no amount of subject-matter aptness fixes that.

What replaced them: three chromolithographs from Annales Musei Botanici Lugduno-Batavi volume 1 (1863), picked by Ryan off the BHL Flickr stream. All three are Emrik & Binger of Haarlem, each with a different draughtsman, and they sit on the vellum as if they were always meant to.

The lesson generalises, so it is written down here rather than left in a commit message: on this site the plate is chosen for how it looks on the sheet first and for what it depicts second. An illustration that has to be explained before it earns its place is not earning its place. The idea can survive as prose — Darwin's reversed spiral is still on the sheet, still credited, still doing the same work, quoted and linked instead of mounted, and the section reads no worse for it.

The paste-up: a zine wall in a herbarium register (2026-09-08) Link to this section

Ryan, briefing the Wyrd sheet: "For this piece, play with the typography. Take inspiration from Zine walls." The risk in that brief is obvious — a photocopied flyposted wall and a Victorian specimen sheet are not the same object, and grafting one onto the other gets you Star Stuff with grain on it, which is the palette rule's failure mode wearing a different hat.

What made it work was noticing they are the same object. A zine wall and a herbarium sheet are both things cut out, laid down at an angle, and fixed where they overlap. One uses masking tape and the other uses gummed linen strips. So the new section in queering.css builds the wall out of furniture the site already owns — the card, the rule, the accent colour that is already the tape on a plate card — rather than importing a second visual language.

Three components, all of them CSS over ordinary semantic HTML:

Rotation is stated per element in the markup as --rot. Same reasoning as .qe-poem .l-in: an nth-child rule silently re-angles the whole wall the moment a slip is added or removed, and a slip's angle is a fact about that slip.

.qe-cutup uses inline-block, not flex, and that is load-bearing. With flex items the words look identical and copy out — and get mirrored into SKS — as oddifficultimmature. Inline-block keeps the whitespace between them as real text nodes.

No new motion. The site's one motion idiom is growth, and slips settling onto a wall is a different idiom. The header drawing animates; the wall does not. Adding a second motion vocabulary for one page is how a design system starts to have dialects.

The third slip is set in the reader's system face (2026-09-08) Link to this section

In .qe-drift, the two older states of the word are Fraunces with the WONK axis on. The third — weird meaning "odd-looking, strange, disturbingly different", from about 1820 — is .qe-drift-word--flat, set in system-ui. When the word stops meaning fate and starts meaning deviation, it is being spoken by an institution, and an institution's typeface is whatever the form was printed in.

It is the one place on the site where a hardcoded font stack is deliberate rather than a mistake. The joke disappears in plain view, where every face is that face, and that is correct: plain view drops decoration, and this is decoration. The slip's own gloss says out loud what the typography is doing, so a reader who cannot see it is not missing the argument.

The measure held, and the drift rail became a column (2026-09-08) Link to this section

The rail wants to be read across, as a timeline. Three states across the 448px measure give 136px each, which is not enough for the gloss under each word; two across gives an orphan.

The tempting fix was a third exception to the measure — main is capped at --qe-measure, and only the masthead and the provocation break it today. It was not taken. The rail runs down the sheet instead, at minmax(16rem, 1fr), which inside 448px is always one column. It is still a sequence; that is what the <ol> is for. One fewer exception is worth more than one better timeline.

Related, and caught by measuring rather than by looking: .qe-wall first shipped at minmax(13.5rem, 1fr). Two 13.5rem tracks plus the 1.25rem gap need 452px and the measure gives 448, so the wall silently collapsed to one column at every window size — a stack of slips, which is a list, not a wall, and it looked deliberate. This is the identical failure the plate grid shipped at 14rem, already recorded above. Found the same way, by reading the computed grid-template-columns in the browser. It is now 12.5rem, the same number the plate grid landed on, for the same arithmetic.

The Wyrd sheet mounts two plates, and Helen picked them (2026-09-08) Link to this section

Superseding the entry that stood here, which said this sheet carried no plate because the paste-up was the image, and guessed that if one were ever added it would want to be fungi in the changeling section.

Half right. A plate did want to go in the changeling section. It is not fungi:

Both were chosen by Helen Edgar, and the captions say so. That is not politeness. On a sheet whose whole credit question was settled two entries down, "chosen by" is a real contribution with a real name on it, and it is the kind of thing that evaporates from a page if nobody writes it down.

They vindicate the rule they were picked under: colour first, subject second. Neither had to be justified before it earned its place. Both happen to be apt as well, which is a bonus and not the criterion.

Placement was changed once, and the reason is worth keeping. The Hughes plate first sat between He was convicted of manslaughter and So: no romanticising the fae on this sheet — which split two sentences that answer each other, and made a charming fairy painting the punchline to Bridget Cleary's murder. It now opens the section instead: fairy country, then what the belief actually did, then the refusal. Where a plate sits is an argument, not a layout preference.

.qe-plate-wide came back, exactly as the note said it would (2026-09-08) Link to this section

The entry above records adding and removing .qe-plate-wide the same day, and closes: "If a landscape plate ever lands here again, the rule is one line: .qe-plate-wide { max-width: var(--qe-measure); }."

One landed. Waterhouse's Miranda is 138cm across, and inside .qe-plate's 23rem cap the foundering ship was a smudge in the corner. The class is back, and it is that line, plus a 5in cap on paper so a wide plate still cannot take a sheet of its own.

This is the decision log paying for itself, and it is the argument against deleting entries about things that got removed. The removal note took thirty seconds to write and saved the next session from re-deriving the cap, re-arguing the case, and probably picking a different number.

Sheets have labels, not bylines — settled (2026-09-08) Link to this section

Superseding the entry that stood here for about an hour, which said the Wyrd sheet's byline was Helen's and the This text row carried the caveat. It shipped that way, Helen read it and declined the credit, and the correction is worth keeping in full because the answer was already written down in our own colophon before the sheet was made.

design.html defines a label as "subject, maker, the date of the original, the date of the reading, and who read it," and adds "a specimen is collected, not written." That is an authorship model, not a glossary entry. A sheet is a reading. The person who made the thing being read goes on Maker; the person answerable for the reading goes on Read by. The Woolf and Rossetti sheets do this correctly. The Wyrd sheet reached for a Written by row and broke it, and no caveat underneath a wrong byline fixes a wrong byline.

The rule, for every sheet from here:

Helen's own words for it, which are better than ours: "I can't take any credit beyond you reading my weird stuff." That sentence is the Read by row.

Knock-on, applied the same day. The sheet's kind changed from essay to reading — kicker, plate card, three sibling navs, the social card's kicker — because under this grammar that is what it is. on-being-ill's Read by row went from Helen alone to Helen and Ryan, on Ryan's word. The sheet keeps Helen's title rather than taking one of its own, which is the one place this is untidy: every other reading has its own name (The Army of the Upright, The Die Uncast) with the specimen's title on the label. If a session wants to tidy that, the title is the change and the address can stay — /invention-of-normal does not have to match.

How the drafting is disclosed: the colophon, not the label (2026-09-08) Link to this section

These sheets are drafted in Claude Code sessions and edited by whoever is on the Read by row. Ryan's call, asked and answered: one honest section in design.html, and nothing in the labels.

The argument for a per-sheet row was that this site treats provenance as a correctness requirement and publishes an attribution ledger, so leaving a link in the chain unstated is the one thing that would undercut the ledger if it surfaced later. The argument that won is that the label is about the reading, not the tooling — a tool does not get a row, because a byline is responsibility and a tool cannot carry any — and that the colophon is where this site already explains how it is made.

So the disclosure is a section, Who reads, and who writes, and it is not buried or hedged: it names the drafting, names who directs and edits it, and points at the public ledger. The reason it exists at all is written into it — a site that keeps a ledger of everyone else's words owes an account of where its own came from. If a future session is tempted to trim that section for length, that sentence is the one to keep.

Bek-Pedersen's conclusion stayed on the sheet (2026-09-08) Link to this section

The Weird Sisters section quotes Karen Bek-Pedersen's transcriptions of Holinshed, the First Folio and Theobald. Her own argument is that Shakespeare wrote weyward on purpose, that his three women are witches rather than Fates, and that Theobald's 1733 emendation "bypasses Shakespeare altogether" — which is inconvenient for a sheet about reclaiming the Weird Sisters.

It is quoted anyway, twice, and it gets its own item in What this sheet will not tidy. Taking a scholar's evidence and leaving her conclusion behind is the worst version of the paraphrase failure, because every individual quotation is exact and the page still lies.

An open item for a session in the SKS repo (2026-09-08) Link to this section

Not to be fixed from here. The brief for this sheet carried the citation Wassell, E. (2025). Experiences of autistic joy. Disability & Society, 41(3), 1–26. The article's own first page gives 41(1), 236–261, 2026; 2025 is the online-first date and "1–26" is the page range of an unpaginated online-first PDF. Both the issue and the pages are wrong.

Queering Earth's own copy is corrected. If that citation is sitting in SKS notes, on stimpunks.org, or in anything of Helen's, it wants the same correction — from a session in that repo.

The changelog is an accession register, and it is a page rather than a file (2026-09-08) Link to this section

/changelog exists. Star Stuff has kept one since it started; this site had four sheets, a ledger of everyone else's words, and a growing list of its own corrections — all of it visible only to somebody with the repo cloned. A site that publishes an attribution ledger owes the account of its own mistakes to readers, not just to sessions.

Why a register and not a list of releases. Star Stuff's changelog is a timeline of dated releases tagged New piece, Revised, Fact-check, Site, and porting that shape wholesale would have been the palette rule's failure mode in a new place: the same page with the hue rotated. A herbarium already has this document. The accession register is the bound ledger of every specimen as it entered the collection and of every annotation slip pinned to a sheet afterwards — a re-determination, a corrected locality, an identification withdrawn. So the four kinds of entry are the four things that happen to a herbarium sheet, and they map one to one onto Star Stuff's four without borrowing its words:

Star Stuffherewhat it means
New pieceMounteda sheet, or a plate, went on
RevisedRe-determinedreworked enough that what it shows is different
Fact-checkLabel correctedan attribution fixed, ours included
SiteCabinetthe stylesheet, the tools, the deployment

The tag chips do not use the accent tokens as text. Each kind carries one of the decorative five, and the token is spent on the chip's bottom rule and the entry's left hairline — never on the letters, which are --qe-moss like every other small-caps line here. This is the rule from CLAUDE.md applied to a component that wants colour-as-meaning: the colour sorts, and the words are readable on their own, which is also why the print sheet takes the chips to black and lets the border carry the shape. Verified: check-contrast measures 377 text elements on this page, 0 failures on screen and 0 under print emulation.

Corrections are entries, not an appendix. Six of the entries in the backfill are our own errors — the byline Helen declined, the Wassell citation we were handed, the Miranda caption, the Bridget Cleary sentence, the Walker paraphrase, the pronouns. Each says what it claimed, what it says now, and how it was caught. The page's own note says why they are in the ledger rather than in a drawer, and the sentence to keep if anybody trims it is that on this site the citation is the only evidence a reader has.

The list markers use ::marker, not a ::before glyph. Star Stuff's entry bullets are a content: '★', which puts a decorative character into the accessibility tree. Colouring the native marker gets the same result with nothing to read out.

Backfilled from the commit history, cross-read against this file and ATTRIBUTIONS.md, so that every correction named on the page is one of those two files' own findings rather than a retelling. It groups by accession rather than by commit: the Wyrd sheet, its byline correction, its two plates, and the paste-up CSS are one dated entry, because that is one thing that happened.

Linked from the footer of every page, on the line under the colophon — the same treatment the colophon gets, and for the same reason: it is about the site rather than on the plate, so it does not take a card and a number. It is not in Elsewhere on the plate either. Non-sheet pages do not carry that nav.

Keeping it up is now part of shipping a sheet. A sheet that lands without a register entry is the same omission as a sheet that lands without a social card, and it is worth the same line in CLAUDE.md: mount it, card it, log it.

The Miranda sheet's address names the play, not the phrase (2026-09-08) Link to this section

the-tempest.html is "Miranda: To Be Wondered With", which follows the convention set out above: the filename is the address a reader searching for the source will guess, and the title is what the sheet found in it. A reader who wants this sheet is looking for the play.

The title is Helen's, kept verbatim, and it is not lifted from the specimen. Sheet No. 4 left exactly this untidy on purpose, with a note saying a later session could tidy it. This sheet makes the same choice for a better reason: To Be Wondered With is a deliberate one-preposition turn on Shakespeare's own coinage, which the sheet's second paragraph explains. It is a reading of the specimen rather than a quotation from it, and swapping in a phrase of the play's would delete the argument the title is making.

Helen's Claude laid out Sheet No. 5, and we kept the typography and threw away the hexes (2026-09-08) Link to this section

The Miranda sheet arrived as a finished self-contained page from Helen Edgar's own Claude session — its own :root palette in hex, its own dark-mode block, its own toggle script. The instruction was to adopt the text as written and keep the heading typography and the staging labels. What that meant in practice:

Kept. The leaning title (h1 .qe-lean, one word tilted left and one tilted right in rust), the wobbling section heads (h2 .qe-wobble), rust section heads with a hairline under them, the small letterspaced staging labels (.qe-block-label), the chain of everybody who has staged Miranda, the dashed "will not tidy" panel, and the struck-and-rewritten speaker prefix. All of it is in a restaging section of queering.css and every colour aliases a --qe-* token.

Dropped. The hexes, the prefers-color-scheme block, and the per-page toggle script. This site has one ground and it is paper: a dark mode is not a missing feature here, it is the other site. The draft's body.plain became html.plain, which is where the class actually goes.

Amended 2026-09-08 — the ground has a second state, and this entry was right about what it refused. See The cabinet is the drawer shut, not the lamp switched off below. What arrived with the draft was a generic inverted palette in hex with its own toggle script, and every word above about that still holds. What is shipped now is a herbarium object reached from the tokens: the daylight sheet is still the canonical ground and still the default in print, in the social cards, and for anyone whose machine has no opinion.

Three things the draft got wrong, all of them accessibility rather than taste:

The plate was a hot-link with a placeholder under it. The draft pointed at Wikimedia's Special:FilePath with a JavaScript onerror fallback reading "Plate to be inserted … source a high-resolution scan before publishing." Waterhouse's Miranda had been mounted on Sheet No. 4 that same morning, so the scan, the alt text and the provenance already existed and the sheet mounts the local file. A draft that ships a placeholder is a draft that ships a placeholder — the fallback text reads as finished furniture and would have gone live saying "see note to Helen."

Two citation errors and one attribution error came in with the draft and are recorded in ATTRIBUTIONS.md and in the register: Kathman's volume (59 → 58), Chedgzoy's surname (Chedzoy → Chedgzoy), and Helen's own essay cited with Queering Earth as its publisher at a URL that does not resolve. The last is the byline rule from Sheet No. 4 running in the other direction, and it is the one worth remembering: an attribution can be wrong by claiming too much for us, not only by claiming too much for somebody else.

The header art is wind, and the first wave was clipped (2026-09-08) Link to this section

Sea holly on a ledge, every stem, leaf and tendril bent the same way. The subject is a person bent by other people's weather, so the drawing leans rather than standing up straight; three heads on one crown are the household of three.

Two things were rebuilt. The plant was first drawn at about half the scale it needed and sat in the lower right of the frame with two thirds of the viewBox empty. And a breaking wave in the lower left curled down to y 252 in a viewBox that ends at 238 — the crest, which was the entire point of it, was silently clipped off the bottom and the remainder read as a stray squiggle sitting on the ground line. It is two tendrils out of the same crown now, running low along the ledge and curling at the ends, which is Helen's "squiggles and swirly bits" note and the same device the Wyrd sheet uses. An SVG that overruns its viewBox does not error; it just quietly stops drawing.

Not ported: a check for citation fields (2026-09-08) Link to this section

Two of the three attribution errors on this sheet were wrong numbers and a dropped letter inside a reference list — a volume number and a surname. That is now twice the register has carried a citation handed to us with the wrong issue. It is tempting to write check-references.mjs.

Not yet, and the reason is the standing rule: port a check when the failure it catches becomes possible to catch mechanically. Nothing on disk knows that Kathman is volume 58; the only way to find that is to read Cambridge's listing, which is a human or a web fetch and not a gate. A check could plausibly verify that every .qe-references entry is shaped like a citation and that every URL in one resolves — the Edgar URL would have been caught by the second half of that. If a third bad citation ships, write the link-resolver half. A check that cannot fail is a check nobody reads, and a check that can only verify punctuation is worse: it would have passed all three of these.

Addendum, 2026-09-08, from the Dickinson sheet. Three more bad references, all caught before shipping, so the trigger above has still not fired — but two of them were invented DOIs, and both return 404 from the DOI resolver. That is the first citation error on this site a guard could actually have caught, and it is worth knowing that the DOI half is the trustworthy half: https://doi.org/<doi> with Accept: application/vnd.citationstyles.csl+json returns the registered title, authors, journal, volume, issue, pages and year, so a checker can verify the whole field rather than merely that it resolves. The general URL half cannot be trusted the same way — Medium, doi.org's own publisher redirects, the Poetry Foundation and Harvard all answer a script with 403 or 202 whether the URL is good or not, so a checker reading those as broken would cry wolf on most of the references here. If the check gets written: hard failure on DOIs, advisory at most on everything else.

Sheet No. 6 is titled from Ryan's phrase, not from the specimen (2026-09-08) Link to this section

The first exception to the convention above, made on Ryan's call with the alternatives in front of him. A sheet is a reading or an essay settled that a reading takes its title from a phrase in the work it reads — on-being-ill is "The Army of the Upright", promises-like-pie-crust is "The Die Uncast". The Dickinson sheet was offered three titles out of the poem — Done with the Compass, Rowing in Eden, A Heart in Port — and one out of Ryan's own prose, and he picked The Swell and the Dwell.

It is the right call and the convention survives it. The reason a reading is titled from the specimen is that the title should say what the sheet found. This sheet mounts two poems: Dickinson's and Ryan's reply. "The swell and the dwell of relational tides" is the sentence in which the reading actually happens — it is the frame that lets the poem be about co-regulation — and no line of Dickinson's holds both halves of it, because her poem only has the swell in it. A title out of the specimen would have named half the sheet.

So the rule now reads: a reading is titled from a phrase in the specimen unless the reading's own hinge sentence is somewhere else, in which case it is titled from that. The address still names the work — /wild-nights — which is the half of the split that was always doing the navigational work.

Our own verse gets a component, and it is rust where the specimen is moss (2026-09-08) Link to this section

.qe-verse in queering.css, added for the Dickinson sheet, which is the first one to mount a poem of ours next to a poem of somebody else's.

.qe-poem could not be reused and it was not close. It wraps a <blockquote> with a cite and a citation in the figcaption, because it mounts a specimen. Ryan's reply is not a quotation of anybody, has no source to cite, and putting it in a blockquote would have made the markup say it was somebody else's — on the one site whose stated risk is a wrong attribution.

The distinction is carried by the two things a reader sees first, and both alias tokens:

the specimenour reply
rulemoss, solid, on the leftrust, on top
facethe display face, Frauncesthe body face, Newsreader, italic

And it is never carried by styling alone. .qe-verse-label says whose words these are in words — "In reply — Ryan Boren" — so plain view, a screen reader, a print-out and a stylesheet-less render all still say it. That is the same rule as the <del>/<ins> fix on the Miranda sheet: a distinction that only exists in CSS does not exist.

Every line is its own <span class="l"> with a hanging indent, for the reasons already written down under Verse gets a shared component. There is deliberately no .l-in: the alternating indent is a fact about Rossetti's 1896 compositor and has no business in our verse.

A licensed plate, for the first time (2026-09-08) Link to this section

Every plate on this site until now has been public domain and said so. The Dickinson facsimile is CC BY-NC-ND 3.0, from the Emily Dickinson Archive, and Ryan asked for it by name.

Mounted, with the three conditions met deliberately rather than incidentally — attribution in the caption in the archive's required form, a non-commercial site, and the file unaltered because it was requested from Harvard's own IIIF service at the width we wanted, so the only derivative was made by the rightsholder's own server. ATTRIBUTIONS.md carries the detail and the instruction not to resize the file locally.

What was considered and rejected: mounting the 1891 printed page instead, which is unambiguously public domain and which we had already read in three copies. It would have been the safe choice and it would have been the wrong object — the sheet's argument is about what the printers did to the leaf, and you cannot show that with a picture of the printing.

The precedent this sets, stated so it does not have to be re-argued: a licensed image may be mounted here when the licence permits our use, the conditions are met in the markup rather than in good intentions, and the sheet says on its face that the plate is licensed rather than free. The default is still public domain. We take a rightsholder at their word on a photograph of a flat public-domain original rather than arguing Bridgeman at them, and that is a decision about how this site behaves, not a legal opinion.

Ryan's verse got punctuation and nothing else, and three places say so (2026-09-08) Link to this section

His brief: "Don't revise my writing above except to give the verse proper poetic formatting/punctuation." Five terminal full stops and five commas were added, and not one word, line break or capital was touched — including the lower-case continuation lines, which turn out to be consistent across all eight stanzas and are therefore prosody rather than typing.

The change is disclosed in three places, on purpose: a Reply in verse row in the sheet's label, a full itemised list in ATTRIBUTIONS.md, and the register entry. The reason is the rule the coming-to-terms label already sets — an unmarked edit of our own published text is the same failure as an unmarked edit of somebody else's, and the site just happens to be the injured party. A verse written for one person and mounted on a public plate is exactly the case where that rule earns its keep.

Corroboration means a different library, not a different file (2026-09-08) Link to this section

The Rossetti entry in ATTRIBUTIONS.md says its colon was verified in "two separately scanned copies", and it happened to be two different libraries. The Dickinson sheet nearly shipped a broken piece of type as a variant reading, because the first two scans of page 97 of Poems, Second Series both come out of University of California Libraries holdings and both show line 11 as mocr instead of moor. They agree. They are one witness.

The University of Toronto copy has the word intact, and the sheet now reports the defect as a defect. The rule, written down because "two scans" reads as sufficient and is not: corroboration means a different physical copy, from a different holding institution, digitised by a different pipeline. Two of those three is not enough.

This is not a candidate for a guard script. Nothing on disk knows which library scanned which Internet Archive item, and the identifier suffix that gave it away — dickrich on both — is a convention, not a contract. It is a reading rule, and the place for it is here and in the ledger.

The cabinet is the drawer shut, not the lamp switched off (2026-09-08) Link to this section

Ryan asked what a dark mode here would be, having seen a dark-ground botanical print, and the answer that survived contact with the measurements was dark warm brown, called the cabinet. changelog.html had already been using the word for a year as its fourth entry kind, which is how we knew the idea had a place to live.

A dark green ground was the obvious first guess and it is the wrong one, for a reason that is measurable rather than a matter of taste. Green ground shares its hue with moss, lichen and verdigris — three of the tokens the site is built from — and every accent measures worse against it for no gain: moss text 7.1:1 against brown's 7.2, rust 6.2:1 against brown's 7.3. Pushed to a real forest tone (#223026) nothing but cream clears 7:1 at all. A green ground makes green unusable. It also reads as a stock eco dark theme, which is the "same site in green" failure the palette rules already name, arriving from the other direction.

Brown was the palette's ground all along. The print that prompted this draws its specimens in cream, sage, marigold and coral on near-black — --qe-ink, --qe-lichen, --qe-marigold, --qe-coral as they already stood. The decorative five cross over unchanged, and deliberately still saturated: lifting them to 7:1 was tried first and turns every flower chalky. 7:1 is a rule for letters. Only ink, moss and rust move.

The inversion worth writing down: in daylight a card is lighter than the page, so the page is the worst case for contrast; on a dark ground a lifted card is the worst case instead. Keeping the "cards lift" instinct and solving 7:1 against a lifted panel drags rust to #eab1a3, a pale pink with no rust in it. The cabinet's cards are recessed, which puts the ground back as the lightest surface, keeps rust an ember, and reads better anyway — compartments in a drawer.

Every hex has one copy. The cabinet values are defined once as --qe-cab-* inside :root; the two switch rules — @media screen and (prefers-color-scheme: dark) on :root:not(.daylight), and @media screen on :root.cabinet — contain nothing but aliases of them. There are two switch rules because CSS cannot set a class from a media query, and the alias indirection is what makes that duplication safe: a drifted switch is a missing ground, never a wrong colour. Both are @media screen, so paper is daylight always and the print sheet cannot inherit a ground.

Three things were not token flips, and all three are now tokens rather than literals: the foxed-paper wash, the drop shadow (a near-black that vanishes on a near-black ground), and --qe-flesh, the pale flesh of a specimen. The last was a real bug: a mushroom's stipe was filled with --qe-paper-deep, a colour it matched only by coincidence, so on the dark ground four mushroom stems became holes.

The toggle is three states behind one word, and it is the quieter of the two controls. Plain view changes what the page is and keeps the pill; this changes what the page is lying on, so it is a word and a hairline. With neither class set the machine decides in CSS with no script involved — which is the reason the media query was kept instead of letting the pre-paint snippet resolve everything and collapsing the stylesheet to one block. A reader with light sensitivity and no JavaScript is exactly the reader who should not be handed the bright page. The button therefore names the ground the reader can see, not a preference they have not expressed, and clicking writes the opposite one down.

And a check that only reports is decoration. The new cabinet pass in tools/check-contrast.mjs was wired to print a column before it was wired into the failure total, which would have made it exactly the "check nobody reads" this repo keeps warning about. It is in the gate, and it was verified by breaking a token on purpose.

tools/check-contrast.mjs gates at WCAG AA, not at the house 7:1 (2026-09-08, closed 2026-09-09) Link to this section

Found while trying to make the new cabinet pass fail: a card lifted to 6.0:1 sailed through. CLAUDE.md names the 7:1 target and check-contrast.mjs in the same breath, which reads as though the script enforces the house standard. It did not — needFor() returned 4.5, or 3.0 for large text, and the summary line said AA in as many words. The 7:1 figure was held by hand-chosen tokens and by nothing else.

Logged and deliberately not fixed at the time: raising the gate needed a run to find out what it newly failed, a decision about the decorative-adjacent text that would surface, and possibly a two-tier report rather than a single threshold. Doing it inside the cabinet work would have buried both.

Closed the next day, and the reason it closed cheaply is that the wish got called in. The recessed --qe-paper-deep panel built during the surfaces work drops --qe-moss to 6.90:1 and --qe-rust to 6.21:1 in daylight and passed this script clean. That is the predicted failure, arriving in the working tree rather than in a hypothetical.

Each of the three worries turned out to be answerable:

--aa gates at AA only and prints a line saying the house target is not being measured in that run. It exists so that an argument for a specific colour is an argument somebody makes on the record, rather than a two-line edit to needFor() that nobody reviews.

Verified by making it fail before believing it, which is this repo's rule for a new gate: the recessed panel was put back and reported 6.90:1 and 6.21:1 as UNDER with exit 1; a 2.15:1 colour was injected and reported as FAIL on the other tier with exit 1; --aa passed the same tree with exit 0 and said why. Then reverted, and the clean tree re-run.

One thing this does not fix. A pass here is still not evidence about texture. The tool composites computed colour pairs, so grain under body text passes every number in it. That is a rule in CLAUDE.md, enforced by nothing, and it is the next thing on this list to become possible the day somebody reaches for a background image.


The fox rhyme wraps 13 of 37 lines and that is left alone, because the 1886 printing wrapped six of them too (2026-09-10) Link to this section

Measured on /two-cohabitating-modes: at the full 34rem measure the .l content box is 406px, twelve lines exceed it, and thirteen render on two lines. The worst is "She opened the casement, and popped out her head;" at 498px natural width — it would need the stanza set at 17.7px (0.93em) to fit, against the component's 1.14em. King's hedgehog poem on the same page wraps nothing, 16 lines of 16.

Thirteen of thirty-seven is worse than the case that earned the narrow-screen step-down — seven of Rossetti's twenty-four, at 375px. And it is worse in kind, because the measure is capped at 34rem, so this wraps at every width and no breakpoint can reach it.

Settled: leave it, and say so in the figcaption. The evidence is the source. Halliwell's own 1886 measure broke six of these lines — "and all things / bright;", "hopped out of / bed,", "the gray goose / is dead,", "and gave him / the slip,", "you may go / again," and "She opened the casement, and popped out / her head;", which is our own worst case. Read from the scan of that edition, not inferred. The rhyme has tumbling internal-rhyme lines of forty-plus characters; it did not fit a Victorian nursery-book page either. Our wrapping reproduces the source's condition rather than departing from it, and .qe-poem .l's hanging indent is precisely the device that keeps a wrap from being mistaken for a line the poet wrote.

Rejected: a .qe-poem--long modifier stepping this poem down to 0.93em. It would set one poem smaller than the other on the same page, which is a visual-hierarchy claim — this poem matters less — that nothing supports; and 17.7px is under the house 18–20px floor. Rejected: letting it break the measure. main is capped at 34rem by design and .qe-wide widens nothing on screen.

What would reopen it: a reader saying the wrapped stanzas read as prose. The numbers are here so that conversation starts from them.