How we work

AI drafts. Verification decides what ships.

That sentence is cheap on its own — anyone can write it. What follows is the part that is not cheap: the checks that actually run, how we know they work, and what they do not cover.

Before anything is designed, I read your record

Your old site as it actually looked — the versions the Internet Archive kept, going back as far as it goes — plus whatever is still on your own drives. Brochures, spec sheets, old proposals, the paragraph someone wrote years ago that people in the company still quote at each other.

Two reasons. Most established businesses already said the true thing about themselves once and then lost it in a redesign; finding that sentence is better than inventing a new one. And comparing the old versions against the current one shows what has actually changed about the business, as opposed to what has only changed about the website. Those are different problems and they have different fixes.

The findings come to you in writing before any build decision is made. I do this part myself. It is the step where the work is decided, so it is not one I hand off.

Who "we" means

A specialist is brought in when a job genuinely needs one. So "we" is accurate rather than decorative — but it should not be read as a large team, because it is not one.

What does not change with the size of the job: one person is answerable for whether the result works, and for every promise made to get the work. If something delivered here is wrong, there is no question about whose problem it is.

A draft is not a deliverable

Drafting is fast now, and that is genuinely useful. It is also the part that carries no assurance. A model will produce something plausible whether or not it is correct, and plausible is the failure mode that survives a read-through.

So nothing here ships because it looked right. It ships because something other than the thing that wrote it agreed — a test, a measurement, a second reading, or a gate that would have refused. The work is in building checks worth trusting, and then trusting them instead of ourselves.

What runs on every build

These are not a checklist someone remembers. They are steps in the build command. A build that fails one of them does not produce a deployable site.

  • Attribution

    check-attribution.mjs

    Any personal name, email, phone number or machine hostname reaching a machine-readable surface — meta tags, structured data, comments, package manifests, sitemaps, image metadata, commit author. One deliberate exception exists and is allowlisted as an exact string; a second occurrence fails.

  • Language

    check-spelling.mjs

    Spelling that does not match the house standard, in published output and in source comments alike — because a comment is where the next piece of copy gets written.

  • Credentials

    check-secrets.mjs

    Any credential-shaped string in the built site at all, and anywhere else any that sits on a line naming a credential. Written after finding an access key that had been public for four months — not through a leak, but because the old form needed it in the browser, and it had then been copied into four documents as a convenience. The gate holds no secret of its own; it matches a shape, not a value.

  • Unfilled commitments

    check-placeholders.mjs

    A page reaching the build with a commitment still written as a blank — a response time, a fee, a threshold. A draft that promises something unspecified is worse than no page, so it cannot be published by accident.

  • Content Security Policy

    generate-csp-hashes.mjs

    Any inline script the policy has not been regenerated for. Change a script without rebuilding and the browser refuses to run it.

A check you have never seen fail is not a check

A gate that passes might be working, or might be looking in the wrong place. The two are indistinguishable from the outside, and the second one is worse than having no gate at all, because it comes with confidence attached.

So every gate here has been tested by deliberately introducing the thing it exists to catch, confirming it fails, then removing it and confirming it passes.

The first version of our language check flagged aria-labelledby — a required HTML attribute — and the phrase “Aurora borealis.” Both were wrong, and finding them is the point. It located a flaw in its own design before it could apply that flaw to the site.

What we measured

Every figure below carries the date it was taken and, where one exists, the script that produced it. A number without a date goes stale silently and becomes untrue without anybody touching it — the file count here read 31 for a few hours on 2026-08-28, which was correct when measured and wrong as soon as a page was added. Worse is a number that was never repeatable in the first place, which the contrast figure below turned out to be. Both failures are described where they happened rather than quietly corrected.

These are run deliberately before a release. They are not build gates: one runs the build twice, and the other needs a real browser. Calling them gates would overstate what happens automatically, which is the failure this page exists to avoid.

Build reproducibility verify-reproducible.mjs measured 2026-08-30
Two clean builds from the same source produced 172 files with identical SHA-256 hashes — every file in the output, not a sample. The count has moved twice: from 33 when the images and video came into the repository and stopped being fetched from a third party, and from 119 when the photographs on the error page joined them, and again for the page behind the mark, and from 171 when the sitemap stopped being a file kept by hand and a plain-text map for machine readers was added beside it. Both are generated, and both had to be made deterministic to stay in this count: the sitemap dates a page from git, and where git cannot — uncommitted source, or a checkout with no history — from the newest of its source files rather than from the clock, because two builds of identical source that disagree are not two builds of identical source. A count that never moves is a count nobody is re-running.
Color contrast check-contrast.mjs measured 2026-08-30
725 text nodes across 9 pages, each measured against the surface it actually sits on rather than against the page background. 0 failures against WCAG AA. This number was worse than stale on 2026-08-29: it was not repeatable. Four runs of the same script against the same build returned 638, 638, 625, 625, because the script revealed sections and then measured them while they were still fading in. The script now stops all transitions before it measures, and repeated runs return the same figure. The count moves when the site does — it was 638 before the error page gained a photograph, 640 before two more gates were listed on this page, 646 before a ninth page existed, 706 before the footer began printing what each page weighs, 715 before this table gained the row below it, 719 before the case studies on /work/ stopped asserting their results and started measuring them, and 724 before the contact form began saying out loud what a message carries. A figure that changes between runs of the same script was never a measurement, and this one was published here for a day.
Structured data against the copy check-structured-data.mjs measured 2026-08-30
Nine page graphs, and 12 questions and answers checked word for word against the visible text of the page carrying them. The schema and the copy are generated from one array, so they agree today; the check exists so they cannot quietly stop agreeing. It was tested by being made to fail on 2026-08-30 in four ways at once — an answer altered so it no longer matched the page, a reference pointed at an identifier nothing defined, an unmeasured priority field put back into the sitemap, and a link added to an address that was never built. Four planted, four caught, and it passed again once they were removed.
Gate verification measured 2026-08-30
Gates are tested by being made to fail. The attribution gate was given five planted leaks across five categories; it caught all five, reported each in the right category, and passed again once they were removed. The credentials gate was tested the same way on the day it was written — a key-shaped string in the built output, one on a line naming a credential in source, one in a document, and two non-UUID token formats — five planted, five caught, each in the right category. The same exercise found a real hole on 2026-08-30: the language gate was not reading the directory its own checkers live in, so a misspelling planted in a script passed. It was the second gate found with that blind spot — the first was the attribution gate, two days earlier. A gate that does not scan the tools that build the site is checking the easy half. The attribution gate was extended the same day to fail on the presence of a metadata block in any delivered image rather than on its contents, and tested the same way: three planted, three caught.

What this costs

Every job is scoped before it is quoted, so there is no price list. Two things can be said before we ever talk.

There is a floor, and work below it is turned down rather than discounted — a job priced under what it takes is a job that ends badly for both sides. The figure is quoted in the conversation, not published here.

The first step is a paid review — the archive and inventory work described above — quoted and agreed before it begins. You get the findings in writing, and they are yours whether or not the build goes ahead. It is the one part of any engagement that can be scoped exactly, which is why it comes first.

If what you need is smaller than that, say so anyway. Sometimes the honest answer is a two-hour fix and an invoice for two hours, and sometimes it is the name of somebody better suited to it.

What your browser reaches

Fonts, images and video are all served from this site itself, and there is no analytics script of our own on any page. Two third parties are reached anyway, and they are named here because naming them is more useful to you than an absolute would be:

  • Cloudflare hosts the site and provides its edge analytics, so it sees the request.
  • Web3Forms relays the contact form, so it handles what you type into it.

There were three until 2026-08-29. An image CDN served the artwork, which meant this site could not actually be moved to another host without taking its pictures from somewhere else — so a claim we make on the work page was not true. The images now ship with the site.

That list is checkable against the site's own security policy, which has to permit each of them by name before your browser will connect.

What this does not cover

A page like this is worth less than nothing if it only lists strengths, so here is the other side.

  • Gates catch the categories they were written for. They will not catch a bad judgment, a wrong approach, or a claim that is accurate and still unwise. Those need a person, and they remain the harder problem.
  • Every figure above was measured on this site. Client results are not published without written consent. We do not have it, so there are none here — rather than something vaguer standing in for them.
  • This is a small practice. What is described is one operator's discipline made mechanical so it does not depend on attention or memory. It is not a large team, and the method is the reason that is not a limitation.
  • None of it is novel. Release gates, reproducible builds and adversarial testing are ordinary engineering. The only claim being made is that they are applied here, on this site, and can be checked.

If that is how you would want it done

Tell us what you are working with and what it is stopping you from doing. You will get a considered reply from someone who read it.