Skip to content

How this site is built

One Python file, and a build that refuses to ship

This site is the only web work here you can inspect without asking anybody's permission, so it is the one making the argument. 114 pages come out of a single generator with no framework under it, 31,405 assertions decide whether they are allowed to exist, and 370 deliberate sabotages prove those assertions are not decoration. Every number here was measured on the date below, and the commands are included so you can disagree with them.

  • Standard library only
  • 31,405 assertions
  • 370 mutants, all caught
  • Two defects found here

Measured

What it is

The generator is one Python file of 21,633 lines, and it imports the standard library and nothing else. There is no node_modules, no bundler, no CSS framework and no content system: the page you are reading was an f-string a moment before it was HTML. That is not minimalism for its own sake. A dependency is a thing that can change under you between two deploys, and a site whose only dependency is the interpreter can still be rebuilt in two years by somebody who is not us.

The generator being the source of truth is the rule that costs something: the HTML is output, so editing a built page is work the next build deletes without mentioning it. The stylesheet and the demo widgets are the exception, because they are hand-written files the build copies rather than emits.

What refuses to ship

A second script, 6,529 lines of it, reads the built HTML and never imports the generator — so it checks the output rather than agreeing with the thing that produced it. 31,405 assertions run over 114 pages, and most of them are not about markup. They are about claims:

  • No price on any published surface. A currency symbol in a page body fails the build, deliberately, because what a job costs belongs in a written scope rather than on a page that cannot ask what the job is.
  • No partnership, certification or approval we do not hold, and no claim about staff numbers or trades we cannot put a name against.
  • Where a page publishes structured data, the machine-readable copy has to refuse what the page refuses. No rating nobody left, no credential we do not hold, no figure for what a job costs, no url the deploy does not serve, and no date later than the day the build was made — because a graph is the one surface here that only a crawler reads.
  • A page that names a measured Niagara version carries the caveat that a different version is a different answer, verbatim, because a number measured on one install is not a fact about the framework.
  • Every demo says on the page that it is simulated, and stays out of the index while an indexable page explains it.
  • Every indexable page needs three inbound internal links. Two means the index and one sibling; three means something chose it.
  • A case study's proof link has to be a public repository or a named forum thread — not a brochure, not a front page, not a link we liked. That gate is the reason this page is not itself a case study: the generator's repository is private, so the evidence would fail our own test.

The deploy runs the same gate again against a throwaway clone of the committed tree, so a pass in a dirty working directory cannot ship. A git push publishes nothing here; one script does, and it takes a lock first.

Gates on the gates

An assertion nobody has watched fail is an assertion nobody has tested. A third script breaks this site on purpose, 370 ways, one at a time: it reverts the tagline, claims a partnership we do not have, publishes a price on a service page, points a case study's proof link at a forum front page, deletes a container from a stylesheet rule. Each mutation names the failure it expects, and one that produces the wrong complaint is reported as loudly as one that produces none. Then it restores the tree and says whether the restore was clean.

Both gates, 2026-10-04. The check.py line is the run that released this
page. mutate.py ran on the same tree, immediately before its own output
was spliced in here - a transcript cannot contain the run that reads it.

$ python3 check.py
31405 passed, 0 failed, 114 pages

$ python3 mutate.py
baseline: check.py passes on the scratch copy (370 mutations)

  CAUGHT      claim-tridium-partner                  1 of 1 failure(s) name it
  CAUGHT      claim-iso-9001                         1 of 1 failure(s) name it
  CAUGHT      proof-link-points-at-a-forum-front-page 1 of 1 failure(s) name it
  ... 289 more, every one caught ...
  CAUGHT      underline-rule-drops-table-cells       1 of 249 failure(s) name it
  CAUGHT      underline-rule-drops-step-bodies       1 of 232 failure(s) name it
  CAUGHT      prose-link-in-an-unmarked-block        1 of 2 failure(s) name it
  CAUGHT      source-count-no-longer-stated          1 of 1 failure(s) name it
  CAUGHT      tool-count-in-the-faq-drifts           1 of 1 failure(s) name it
  CAUGHT      service-count-in-the-index-lede-drifts 4 of 4 failure(s) name it
  CAUGHT      transcript-names-a-page-that-moved     1 of 2 failure(s) name it
  CAUGHT      a-route-is-stated-twice                1 of 2 failure(s) name it
  CAUGHT      301-and-stub-disagree                  1 of 1 failure(s) name it
  CAUGHT      tool-card-dropped-from-the-hub         1 of 1 failure(s) name it
  CAUGHT      licence-block-claimed-but-not-in-the-file 1 of 3 failure(s) name it
  CAUGHT      licence-block-in-the-file-but-not-claimed 1 of 1 failure(s) name it
  CAUGHT      handoff-warranty-window-drifts         1 of 2 failure(s) name it
  CAUGHT      hosted-script-gains-fetch              1 of 6 failure(s) name it
  CAUGHT      llms-txt-total-rots                    2 of 2 failure(s) name it
  CAUGHT      hosted-scripts-claim-a-notice-none-carries 1 of 5 failure(s) name it
  CAUGHT      hosted-notice-claimed-nowhere          1 of 1 failure(s) name it
  CAUGHT      hsts-note-states-a-longer-promise      1 of 1 failure(s) name it
  CAUGHT      hsts-constant-moves-without-the-page   1 of 1 failure(s) name it
  CAUGHT      hsts-one-way-door-reasoning-dropped    1 of 1 failure(s) name it
  CAUGHT      hsts-page-stops-saying-neither-is-sent 1 of 1 failure(s) name it
  CAUGHT      service-page-drops-its-support-band    1 of 1 failure(s) name it
  CAUGHT      two-service-pages-share-one-support-sentence 1 of 1 failure(s) name it
  CAUGHT      support-page-charges-for-the-warranty  1 of 2 failure(s) name it
  CAUGHT      support-page-promises-a-monitoring-desk 1 of 1 failure(s) name it
  CAUGHT      support-page-warranty-window-drifts    1 of 1 failure(s) name it
  CAUGHT      service-page-drops-the-demo-it-sells   1 of 1 failure(s) name it
  CAUGHT      service-page-drops-the-work-that-proves-it 1 of 1 failure(s) name it
  CAUGHT      demo-stops-saying-its-station-is-simulated 1 of 2 failure(s) name it
  CAUGHT      case-study-claims-a-label-the-demos-dropped 1 of 4 failure(s) name it
  CAUGHT      css-note-states-a-stale-stylesheet-size 1 of 1 failure(s) name it
  CAUGHT      css-note-median-drifts-from-the-recount 1 of 1 failure(s) name it
  CAUGHT      css-note-counts-the-runtime-rule-as-deletable 1 of 1 failure(s) name it
  CAUGHT      css-note-font-figures-drift-from-the-files 1 of 1 failure(s) name it
  CAUGHT      css-note-drops-a-rule-that-is-still-dead 1 of 231 failure(s) name it
  CAUGHT      css-note-calls-a-used-rule-dead        2 of 8 failure(s) name it
  CAUGHT      mono-preload-returns-to-a-page-with-no-mono 1 of 2 failure(s) name it
  CAUGHT      mono-preload-dropped-from-a-page-that-draws-mono 1 of 2 failure(s) name it
  CAUGHT      sheet-note-rule-count-drifts           1 of 1 failure(s) name it
  CAUGHT      sheet-note-understates-the-unrepresentable-share 1 of 1 failure(s) name it
  CAUGHT      sheet-note-inflates-the-variant-share  1 of 1 failure(s) name it
  CAUGHT      sheet-note-drops-the-nothing-evaluated-limit 1 of 1 failure(s) name it
  CAUGHT      sheet-note-loses-the-link-to-the-service 1 of 4 failure(s) name it
  CAUGHT      sheet-band-loses-the-link-to-the-measurement 1 of 2 failure(s) name it
  CAUGHT      sheet-band-drifts-from-the-note        1 of 1 failure(s) name it
  CAUGHT      sheet-record-url-count-edited-to-fit   1 of 1 failure(s) name it
  CAUGHT      sheet-record-drops-the-nothing-evaluated-method 1 of 1 failure(s) name it
  CAUGHT      sheet-record-loses-the-one-exception   1 of 1 failure(s) name it
  CAUGHT      schema-claims-a-review-nobody-left     1 of 1 failure(s) name it
  CAUGHT      schema-prices-a-page-that-never-says-free 1 of 1 failure(s) name it
  CAUGHT      schema-breadcrumb-passes-through-its-own-page 1 of 1 failure(s) name it
  CAUGHT      transcript-assertion-total-is-from-an-older-run 1 of 1 failure(s) name it
  CAUGHT      chip-row-mutant-count-is-from-an-older-run 1 of 1 failure(s) name it
  CAUGHT      transcript-baseline-is-from-an-older-run 1 of 4 failure(s) name it
  CAUGHT      transcript-page-count-ages             1 of 1 failure(s) name it
  CAUGHT      transcript-publishes-a-run-that-failed 1 of 1 failure(s) name it
  CAUGHT      transcript-summary-is-from-a-shorter-run 1 of 1 failure(s) name it
  CAUGHT      transcript-admits-a-miss-and-the-page-still-ships 1 of 1 failure(s) name it
  CAUGHT      transcript-elides-more-rows-than-it-ran 1 of 1 failure(s) name it
  CAUGHT      transcript-gains-a-row-nobody-ran      1 of 3 failure(s) name it
  CAUGHT      closing-sentence-counts-the-rows-of-an-older-build 1 of 1 failure(s) name it
  CAUGHT      catalogue-grows-past-the-transcript    1 of 3 failure(s) name it
  CAUGHT      note-count-in-digits-ages              1 of 3 failure(s) name it
  CAUGHT      engineering-note-count-ages            1 of 2 failure(s) name it
  CAUGHT      home-page-note-count-ages              1 of 1 failure(s) name it
  CAUGHT      tool-count-in-digits-ages              1 of 2 failure(s) name it
  CAUGHT      group-count-ages                       1 of 2 failure(s) name it
  CAUGHT      demo-count-in-digits-ages              1 of 2 failure(s) name it
  CAUGHT      count-sentence-reworded-out-of-its-gate 1 of 1 failure(s) name it
  CAUGHT      a-note-the-hub-does-not-list           1 of 28 failure(s) name it
  CAUGHT      teaser-keeps-a-figure-the-note-moved-past 1 of 1 failure(s) name it
  CAUGHT      description-publishes-a-figure-the-body-does-not 1 of 1 failure(s) name it
  CAUGHT      spelling-a-service-page-switches-english 1 of 1 failure(s) name it
  CAUGHT      spelling-a-case-study-switches-english 1 of 1 failure(s) name it
  CAUGHT      spelling-a-hub-switches-english        1 of 1 failure(s) name it
  CAUGHT      closing-clause-group-count-retyped     1 of 2 failure(s) name it
  CAUGHT      closing-clause-miscounts-a-described-gate 1 of 1 failure(s) name it
  CAUGHT      closing-clause-counts-a-gate-nobody-wrote 1 of 1 failure(s) name it

370 caught, 0 not caught, restore clean

The last seventy-eight are the gates this page's own claims rest on: two
delete a container from the stylesheet rule, one puts a link in running text
on the home page, one separates a line count from its unit so the size claim
here stops matching, one lets a published tool count age behind the list it
describes, one does the same to the service count, which had already drifted
in public, one renames a page the Lighthouse table above scored, so the
published evidence points at a 404, one states the same route twice, one
points a real 301 somewhere other than the stub beside it, which is how a
moved page loses the ranking it had, one points a tool's own card at the hub
instead of the tool, which leaves a published page with nothing linking to
it, two hold the licence sentence to the served bytes in both directions -
one takes the notice out of a script the sentence says carries it, one lets
the page go quiet about notices that are in every file, one moves the
correction window on /handoff/ off the number the subcontract mails state,
one puts a fetch() into a script the hosted EDE checker loads, which is the
whole of the only promise that page makes - that a visitor's file never
leaves it, one ages the tool count in llms.txt, the brief written for
machines to quote, which had said two for as long as there were thirteen
because nothing here read it, two do the same for the browser version's own
licence, which the glob behind the first pair never walked, four hold this
host to the advice in its own note on redirecting http to https - one lets
the page publish a longer promise than anybody decided to send, one moves
the generator's number without the page following it, one drops the
reasoning that makes a one-day promise a decision rather than a shrug, and
one lets the page go quiet about the two directives it says this host does
not send, two hold the answer a buyer wants after the price, what happens to
me in month two, on every page that makes an offer - one points a service
page's support band at the contact form instead of the page stating what
support is and is not, and one pastes one page's sentence onto a second,
which is the shape a band like this rots into when nobody counts, three hold
/support/ to the distinction it exists to draw - one puts the paid-support
sentence ahead of the free correction window, which is how a page ends up
charging for its own warranty, one gives the page a monitoring desk nobody
here staffs, and one moves the correction window off the number /handoff/
publishes, two hold the reverse edge of a case study's proof list - one
sends a service page's demo card back to the work index, and one does the
same to the case study whose own proof list the band is derived from, which
is the direction this site shipped without, two hold both ends of a claim
one page made about three others - one takes the simulated-station label off
a demo document, and one lets the interfaces case study keep telling readers
that every demo page carries it after the demos stopped saying so, six hold
the first note here written out of a measurement rather than a keyword to
the files it was measured from - four let a published figure drift off the
stylesheet, the fonts or the recount, one adds a rule nothing can reach that
nobody has named, and one lets an exception kept on purpose outlive its
reason, two hold both ends of the preload fix that note reports - one
promises a page 40,604 bytes of mono face with no mono glyph on it, and one
lets a page that draws one announce nothing, ten hold the first note here
whose evidence is a committed record rather than this site's own files -
three let a published figure drift off that record, one drops the limit that
bounds every other figure on the page, two cut the link between the note and
the service page it is evidence for, one lets that page's proof band
disagree with the note, and three edit the record itself to agree with a
page, three hold the machine-readable copy of a page to what the page itself
refuses, which is the one surface here only a crawler reads - one gives a
graph a rating nobody left, one puts a price on a page that never says free,
and one sends a breadcrumb trail through the page it is supposed to lead to,
eleven hold this page's transcript of its own two runs to the chips above it
and to the catalogue below, which is where the two forms of one claim had
already drifted apart in public - four let the transcript or its chips keep
an older run's totals, one publishes a run that failed, one admits a miss
and ships anyway, three break the arithmetic between the rows it shows, the
rows it says it elides and the total, one lets the sentence that counts
these very gates count the wrong ones, and one moves the catalogue out from
under the page, ten hold the figures this site publishes about its own
catalogue, which were stated in digits on more than one page and read once -
six let the count of notes, tools, groups or demos age behind the tree it
describes, one rewords a count sentence out of its own gate, one publishes a
note the hub does not list, and two let a teaser or a search-result
description quote a figure the page it summarises does not state, three hold
one English across every page - one switches a service page to the other
side of a pair this site only ever writes one side of, one a case study, one
a hub, because a site written page by page drifts between spellings long
before anybody reading it says so, and three hold the arithmetic of this
very sentence - one retypes a group's count, one miscounts the gates a
clause describes, one inflates a count at the top level, because every
figure in it was written by hand against a generated list and the total
above can stay true while the clauses under it stop adding up.

We measured our own pages, and two of them failed

None of that says anything about whether the pages are any good to use. So five of them went through Lighthouse under mobile emulation: the home page, a page about what ships with a job, a free tool, a case study and a note. Three came back at 100 across accessibility, best practices and SEO. Two came back at 95, both for the same rule.

Lighthouse 13.4.1, mobile emulation, navigation mode, 2026-10-03.
Scores are out of 100. The performance category is not in this run;
Lighthouse takes it from a trace, not from this audit.

  a11y  best  seo   failed  url
   100   100  100        0  https://plantroomlabs.com/
   100   100  100        0  https://plantroomlabs.com/handoff/
   100   100  100        0  https://plantroomlabs.com/tools/module-sign-scan/
    95   100  100        1  https://plantroomlabs.com/work/decoder-upstream/
    95   100  100        1  https://plantroomlabs.com/notes/niagara-poll-rates-and-tuning-policies/

The two 95s are one rule, axe link-in-text-block:
  ol.pl-steps > li > div > a  ->  1.39:1 against the text around it
  tbody > tr > td > a  ->  1.22:1 against the text around it

The rule is that a link sitting inside running text has to be distinguishable without colour. This site's accent measures 1.39:1 against the text around it in one case and 1.22:1 in the other, where the standard asks for 3:1, and neither link carried an underline. The stylesheet had the rule already, written with a comment explaining why it is scoped to prose containers. Its selector list simply never reached a step body, which lives in a bare div, or a table cell.

So the rule was extended to both — and then the same question was asked of every page rather than only of the two that were measured. With the two selectors reverted on a scratch copy, the gate reports exactly what the old list left unmarked across all 114 pages: ten links on ten pages, seven in table cells and three in step bodies. A sweep written by hand first reported only the seven, because it did not count a step body as a block in its own right — which is the argument for gating the rule rather than sweeping for it, and a page about measurement should say when the first measurement was wrong. Both audited pages re-measure at 100: the case study and the note are the two, and the fix is live on this page as well.

The part that matters more than the fix: the gate now reads that selector list back out of the stylesheet and fails the build if a page puts a link in running text the stylesheet cannot reach, or if the rule loses one of its containers. Three of the sabotages above are that gate — two delete a container, one adds a bare link to the home page. The defect was found by measuring, and it is now held by a test rather than by anybody remembering it.

Then the two pages that went up today

Two more pages were published on 4 October: website design and the workbook audit. The first of those sells a measured handover, so publishing it without measuring it would have been the exact defect it is about. Both went through the same audit on the published URL the day they went up.

Lighthouse 13.4.1, mobile emulation, navigation mode, 2026-10-04.
The two pages published that day, on the live URL, plus the home page again.

  a11y  best  seo   failed  url
   100   100  100        0  https://plantroomlabs.com/services/website-design/
   100   100  100        0  https://plantroomlabs.com/services/spreadsheet-to-web-app/
   100   100  100        0  https://plantroomlabs.com/

The home page is in this run because the row for it in the table above had no
saved report behind it. It measures the same.

Both new pages were also audited against a local copy of the same bytes, where
best practices comes back at 96 and not 100, for one reason: the analytics
beacon cannot load from 127.0.0.1, so the console carries one network error.
That is the harness, not the page.

What a first visit costs

Measured against the live domain, with the compression a browser asks for:

Measured 2026-10-03 against the live site, with the compression a browser asks for.
Every row is one request. Sizes are bytes on the wire.

   bytes  encoding  url
   13758  br        /
     263  br        /assets/mark.svg?v=b3d8ec4a5542
    2779  br        /assets/favicon.ico?v=503bf7424a89
    5408  identity  /assets/apple-touch-icon.png?v=76d34265a138
   64388  identity  /assets/fonts/inter-var.woff2
   40604  identity  /assets/fonts/jetbrains-mono-var.woff2
   18989  br        /assets/css/plantroom.css?v=402c241bcabb
    2999  br        /assets/js/site.js?v=f69df5f76fc6

8 requests to this origin, 149188 bytes.
Of that, 104992 bytes is two variable font files, which is 70 per cent.
One request leaves this origin on every page: the Cloudflare analytics beacon.

Cache headers, read from the same responses:
  /                       cache-control: public, max-age=0, must-revalidate
  /assets/... (any asset) cache-control: public, max-age=31536000, immutable

Two variable fonts are 70 per cent of that, which is the honest cost of not using the system stack, and the only request leaving this origin is the analytics beacon. Everything under /assets/ is served immutable for a year and carries a content hash in its URL, so a changed stylesheet is a new URL and an unchanged one is never fetched twice. That header is also a trap worth naming: on a stable filename it would mean a CSS fix reaching nobody who had visited before, for up to a year. The hash in the URL is what makes the header safe, and the build computes it rather than a person.

What this does not prove

The repository is private, so you cannot read the generator or the gates, and a screenshot of a passing test proves nothing. What is checkable is the output, from outside, without an account:

  • curl -sI https://plantroomlabs.com/assets/css/plantroom.css — the cache header, and the content hash in the URL above it.
  • Lighthouse, in your own Chrome, on any page here. The table names the version, the emulation and the date, and three of those five pages are the ones a stranger is most likely to land on.
  • Read the page source. There is no bundle to unminify, and the only third-party script on any page is the beacon.

Two things this page deliberately does not claim. There is no performance score here: the audit that produced that table does not include the category, Lighthouse takes it from a trace instead, and quoting a number from a different run would be a different measurement. And none of this is a traffic claim — the search numbers for this domain are small and new, and a page about how a site is tested would be a strange place to pretend otherwise.

What it is offered as is evidence for one line on the web, apps and DevOps page — a build that refuses rather than ships when a check fails — written out at the only address where you can check the claim against the bytes.

Next step

Want this done to something that is already live?

Send the address. What comes back is the same kind of measurement as the one above, against your site rather than ours: what is actually wrong, with the command that shows it, and nothing invented. If nothing is wrong, that is the answer and it cost you one email.