Lee Painter Music for the Soul. Code for the Bowl.

Think Log

A change log for the things I built, changed, removed, noticed or started questioning.

11 September 2026

Your SaaS ARR might just be an implementation detail.

There’s a particular category of AI SaaS that increasingly makes me nervous.

It finds leads.

Processes receipts.

Handles email.

Researches companies.

Takes some AI behaviour, wraps it in an application, puts Stripe in front of it and charges $99 a month.

But what happens when the behaviour itself becomes portable?

Yesterday I realised I could build and test one of those behaviours myself in a couple of hours.

The SaaS company might have millions in ARR.

But the thing I’m actually paying for could increasingly be described as:

A behaviour I haven’t created yet.

That’s an uncomfortable place to build a moat.

10 September 2026

Free means removing reasons not to try it.

I’ve been thinking about what “free software” actually means from the user’s perspective.

Free.

But register first.

Free.

But give us your email address.

Free.

But only for 30 days.

Free.

But only five users.

Free.

But you’ll need a credit card.

Every qualification creates another reason not to bother.

With one of our new products I’ve increasingly found myself wanting to remove all of them.

No registration.

No time limit.

No artificial limits.

Download it.

Use it.

Scale it.

If it’s useful, keep using it.

If you need our expertise, we’re here.

Maybe free isn’t a price point.

Maybe it’s the absence of friction.

9 September 2026

The most plausible explanation isn’t necessarily the right one.

A customer upgraded from version 1.6 of our SSH server to 1.7.

Their SFTP client stopped working.

The obvious conclusion:

Something changed in 1.7.

So we investigated.

Except the relevant code hadn’t materially changed.

Eventually we found the problem.

It was in their implementation.

They were using the wrong constructor when adding SFTP attributes to the response, producing malformed data that another SFTP client couldn’t parse.

Nothing we’d changed had caused it.

This is one of those debugging traps that’s incredibly easy to fall into.

A changed.

Then B broke.

Therefore A caused B.

It’s a perfectly reasonable hypothesis.

It’s just not evidence.

The most plausible explanation is where you start investigating, not where you stop.

8 September 2026

The QR code you’re not allowed to scan.

US immigration.

There’s a large sign advertising an app that supposedly makes getting through customs easier.

The sign contains a QR code.

Alongside it are warnings that photography isn’t allowed.

A QR code.

In a place where you’re told not to use your camera.

I couldn’t even take a photograph of the absurdity because, well, photography isn’t allowed.

This might be my favourite example yet for the Common Sense Police.

Technology doesn’t improve a process simply because you’ve added technology to it.

At some point, somebody still has to ask:

Can a human actually do what we’re telling them to do?

7 September 2026

I learned to make things before I learned how I was supposed to make them.

I’ve realised recently that my music and software careers followed almost exactly the same pattern.

Make something.

Observe it.

Understand it.

Improve it.

Then learn the terminology and processes that explain what you’ve already discovered.

As a young songwriter, I could put an odd bar into a song because I could hear that the song needed it.

I didn’t necessarily have the musical vocabulary to explain what I’d done.

Software wasn’t much different.

Build the thing.

Solve the actual problem.

Then learn which established practices help you do that more reliably.

I’ve never been particularly interested in following a process simply because that’s the process.

The method serves the outcome. Not the other way around.

4 September 2026

The definitive record isn’t necessarily the definitive truth.

I’ve learned rather more about public footpaths recently than I ever intended to.

One thing has stuck with me.

We have a tendency to assume that because something is recorded in an official system, the thing being recorded must therefore be correct.

But a record is still a record.

Someone created it.

Someone interpreted evidence.

Someone entered information.

Someone may have made a mistake.

That’s true of maps.

Databases.

CRM records.

Asset inventories.

Security systems.

Pretty much everything.

Authoritative data can still be wrong.

Sometimes the real problem isn’t reality failing to match the record.

It’s the record failing to match reality.

3 September 2026

Security questionnaires can’t patch obsolete software.

A customer using a very old version of one of our products recently sent us a detailed security assessment.

Lots of good questions.

Development practices.

Vulnerabilities.

Security controls.

Processes.

All perfectly reasonable.

Except they’re still running software that reached end of life years ago.

There’s something slightly backwards about applying increasingly sophisticated governance around software you’ve chosen not to modernise.

Security isn’t just the process surrounding the software.

The lifecycle of the software itself is part of your security posture.

2 September 2026

Urgency has a half-life.

We’ve been waiting around six months for information from a customer that we needed to investigate their support issue.

The information has finally arrived.

And, naturally, it’s now urgent.

But urgency doesn’t survive six months of inactivity unchanged.

If somebody is waiting on you before they can continue, the clock isn’t paused.

Priorities change.

Other work arrives.

People move on.

We’ll still help.

But your emergency doesn’t automatically become somebody else’s emergency simply because you’ve finally supplied the thing they were waiting for.

Your urgency does not survive your inactivity.

1 September 2026

Today I fixed a bug I wrote 23 years ago.

Some code I wrote in 2003 was parsing an unsigned 64-bit integer using:

new BigInteger(bval)

Which interprets the byte array as a signed two’s-complement value.

It should have been:

new BigInteger(1, bval)

The bug survived for roughly 23 years.

And it turns out there were unit tests for the class.

They just didn’t cover that particular constructor.

Which is perhaps a more useful reminder than there being no tests at all.

Having tests and having coverage of the thing that’s broken are two very different things.

The tests passed.

For 23 years.

So did the bug.

31 August 2026

We talk about “human-in-the-loop” AI as though there is a human sitting somewhere waiting to press Approve.

Organisations don’t really work like that.

Sometimes Alice can make the decision.

Sometimes Alice or Bob can.

Sometimes everyone needs to agree.

Sometimes you need two out of three.

Sometimes the person being asked depends entirely on what is being requested.

That isn’t an approval button.

It’s an organisational decision structure.

If AI is going to operate inside organisations, perhaps human-in-the-loop needs to start modelling how organisations actually make decisions.