// 4 notes written here · 18 threads with a test

Threads

Short, opinionated and runnable. The notes are things that broke while we built vorluno.dev and what held afterwards; the threads are repositories with a claim in the title, the argument in the README and a test that makes it true — clone it, run it, disagree with it.

Written here

  1. note · by Vorluno · Sep 21, 2026

    A stopped Lenis still eats the wheel

    You opened a full-screen menu, stopped the page's smooth scroll, and now the menu itself will not scroll. Nothing is broken. Lenis is doing exactly what it says.

  2. note · by Vorluno · Sep 21, 2026

    The dot grid that froze the phone

    A canvas effect that runs at 60 fps on a laptop can still hang a phone — not because it draws too often, but because it rebuilds too often, on the one thread the browser cannot spare.

  3. note · by Vorluno · Sep 21, 2026

    Cloudflare kept the old face

    The fix was in production for seven hours and the client kept seeing the bug. The CDN was doing exactly what we had asked it to do the day before.

  4. note · by Vorluno · Sep 21, 2026

    Satori does not read woff2

    Generated OpenGraph images fail silently when the font you serve to browsers is not a font the image renderer can parse. The fix is a second copy of the font — in a format the site never ships to users.

One idea per repo

TypeScript · Apache-2.0 · ★ 0 · Sep 7, 2026

A cap in the wrong unit is not a cap you forgot to check

It is one you cannot compare. The action degrades to "ask a human" every single time, nothing errors, and nobody reports it — because asking a human is exactly what a careful system is supposed to do.

TypeScript · Apache-2.0 · ★ 0 · Sep 7, 2026

A gate that answers two questions lies about both

Reusing one signal for a second, similar question works right up until the two answers stop agreeing — and they stop agreeing on the case the gate was built for. The symptom is a check that is correct about everything except what matters.

TypeScript · Apache-2.0 · ★ 0 · Sep 7, 2026

A test you never saw fail proves nothing

And the check that is supposed to prove it — break the code, see if the suite notices — lies back at you in a way almost nobody accounts for: a mutation that comes back green is not evidence until you know it changed something.

TypeScript · Apache-2.0 · ★ 0 · Sep 7, 2026

Autonomy belongs to the capability, not to the agent

One switch for the whole agent forces a choice between an agent that is useless and one that is dangerous. Reading a balance can be automatic while issuing a credit note needs approval — in the same agent, in the same turn.

TypeScript · Apache-2.0 · ★ 0 · Sep 7, 2026

Classify every column, or fail the build

A registry each module reports into cannot see the module that forgot to report — which is the only one you needed it to find. It answers "is everything I was told about classified?", and reports green while an address walks out of an erasure request. A check whose universe is supplied by the thing being checked cannot report an omission.

TypeScript · Apache-2.0 · ★ 0 · Sep 7, 2026

Human approval is not a defence; freezing the arguments is

Around 93% of approval requests are approved without being read. If your defence is that somebody said yes, you do not have a defence. What protects you is that the thing executed is identical to the thing shown, checked again at the moment of execution.

TypeScript · Apache-2.0 · ★ 0 · Sep 7, 2026

Put the second wall where the prompt cannot reach

A guardrail in the prompt is a suggestion — it is made of the same material as the attack. A guardrail in the function that writes is a wall. The difference shows up the moment the model is talked into something, and the wall does not try to win the argument.

TypeScript · Apache-2.0 · ★ 0 · Sep 7, 2026

Refusal reasons are product design, inside a security layer

Six situations that need six different people to do six different things, compressed into one bit. The owner reads "it did not run" and cannot tell whether to change a switch, grant a role, configure a ceiling — or do nothing at all, because it already happened.

TypeScript · Apache-2.0 · ★ 0 · Sep 7, 2026

Row-level security leaks when the connection is pooled

It compiles. The unit tests pass. Two tenants, both correct. And then a background job borrows a connection and reads somebody else's rows — with the policy applied, not bypassed.

TypeScript · Apache-2.0 · ★ 0 · Sep 7, 2026

The append-only table that blocked its own correction

Forbidding modifications is right, and it holds until the day you need to fix an entry that is wrong — and discover your own rule standing in the way of a correction everybody agrees with. What happens next in most systems is a "temporary" admin script with the constraint switched off. From that day the table is append-only in prose only.

TypeScript · Apache-2.0 · ★ 0 · Sep 7, 2026

The key identifies the effect, not the occasion

Deriving the idempotency key from the turn, the request or the run looks reasonable and silently deletes the second legitimate action of the same turn. And there is a second decision nobody writes down — where the key is checked — that duplicates instead of losing.

TypeScript · Apache-2.0 · ★ 0 · Sep 7, 2026

The model may supply search terms, never identifiers

If a model can emit an id, a hostile message can decide which record you act on. If it can only emit search terms, the worst an injection achieves is finding nothing — and the version that would let it through does not compile.

TypeScript · Apache-2.0 · ★ 0 · Sep 7, 2026

Two SDKs, one schema — and where the drift goes next

Two hand-written clients drift. Generate both from one schema and they stop drifting — the drift moves into the generator, where a single missing line is wrong in every language at once, quietly. Then it moves one place further, into the test that was supposed to catch it.

TypeScript · Apache-2.0 · ★ 0 · Sep 7, 2026

You cannot delete what you never encrypted per subject

A soft delete satisfies the right to restrict processing. It does not satisfy the right to be forgotten — and in a database with backups, deleting for real is not something you can do at all. The test is the restore.

TypeScript · Apache-2.0 · ★ 0 · Sep 7, 2026

Your CI gate is green because of a pipe

The exit code of a pipeline is the exit code of its last stage. A check that ends in | tee log.txt or | head -5 reports success no matter what happened on the left, and the error is printed right there in the green job.

TypeScript · Apache-2.0 · ★ 0 · Sep 7, 2026

Your deprecation window cannot be shorter than your oldest pending approval

Thirty days of notice, a changelog entry, a clean removal — and a live Approve button that can never work again, because the thing it would run was frozen against a contract you just deleted. Then somebody patches the error away, and it starts issuing four thousand dollars where forty were asked for. A proposal cannot outlive the contract it was frozen against — so either it expires first, or the