In an infrastructure doc for my home network, I had sized a future single sign-on provider like this:
Authentik is the common answer but wants roughly a gigabyte across four containers. Kanidm — a single Rust binary — or Pocket ID fit this setup more comfortably.
Read that on its own and it is a verdict about Authentik. It is how I read it, several times, over about six weeks. Every time the question of SSO came up I skimmed that line, thought right, too heavy, and moved on to comparing the two lightweight options.
Now read it with the sentence directly above it, which I had also written:
Keeping it at home also keeps the cloud box small, which matters on a 1 GB instance.
It is not a verdict about Authentik. It is a verdict about a gigabyte on a small VPS.
And two sections earlier, the same document had already concluded — for entirely separate reasons, about latency and about not depending on the internet to open my own front door — that the identity provider belongs at home, on the machine with 64 GB of RAM.
So the document contained both halves and never put them together. If the provider runs at home, the gigabyte is spent on a box where a gigabyte is unremarkable. The thing that never fit was not Authentik. It was Authentik on the small cloud instance — a pairing, recorded as a property of one half.
Why this shape survives
A written record keeps the verdict and loses the premise, because the verdict is what you were looking for when you wrote it down.
Think about the moment of writing. You are mid-decision, holding four constraints in your head at once, and the note is a result — the thing you want to be able to look up later so you don’t redo the analysis. The premise feels like scaffolding. It was in your head five seconds ago; it is obviously still true; writing it out feels like padding. So the note captures the conclusion cleanly and the conditions loosely, if at all.
Six weeks later — or six months, or after a team handover — the sentence “Authentik is too heavy” reads as a fact about Authentik. Nobody re-derives it, because it looks derived. That is the trap. It has the form of a conclusion, so it gets treated as one, and re-checking a conclusion feels like distrusting your past self rather than doing the work.
There is a familiar cousin here: the stale document, the one marked living: true that stopped being true in March. But a stranded rejection is harder to
catch than a stale doc, and the difference is worth being precise about. A
stale doc says something that is no longer so. A stranded rejection says
something that is still so, and no longer relevant. Check the stale doc and it
disagrees with the world, and the disagreement is the alarm. Check the stranded
rejection and it agrees — Authentik really does want about a gigabyte, that
number is correct, it was correct when I wrote it and it is correct today.
Verification produces agreement, agreement produces confidence, and the
confidence is misplaced.
The shape of the fix
Write the constraint beside the verdict, in the same sentence, in a form that has an owner. Not “Authentik is heavy” but “Authentik is too heavy for the 1 GB cloud instance”. Six extra words and the note now fails visibly the moment the instance is resized. A verdict without its premise is an orphan; a verdict with its premise is a conditional, and conditionals can be re-evaluated by someone who wasn’t in the room.
Re-open the rejection when the other member of the pairing changes. That’s the operational trigger, and it is worth writing into whatever process you have around infrastructure changes: resizing a box, moving a service, replacing a dependency, upgrading a runtime — each of those is an event that should send you back through the rejections that cited it.
Then ask three questions.
Did the number belong to the tool, or to where it was going to live? This is the one that unpicked my case. Almost every resource-based rejection is secretly about a pairing, because “too big” is meaningless without a container.
Has that half moved? Measure both sides rather than assuming. Mine had: the cloud instance had gone from 1 GB to 2 GB, of which about 300 MB was in use — so a gigabyte genuinely does still hurt there, and genuinely doesn’t on the LAN box. Both halves needed measuring, and neither answer was guessable. If I had assumed the resize made the objection go away, I would have reached the right decision for the wrong reason, and re-derived the wrong reason next time.
Would the rejected option now be chosen on its merits? Here it would, and this is where the strandedness had cost me something real. My own stated reason for building SSO at all was that it teaches something that transfers to professional work. That reason argues for the mainstream tool with the industry-standard connectors and the enormous documentation surface — the exact tool I had ruled out on weight, in a note that never mentioned the goal it was serving.
The generalisation is compact and it has been useful to me well beyond infrastructure: a constraint attaches to a pairing, and gets recorded as a property of one member. Language libraries “too slow” for a workload that no longer exists. A vendor “too expensive” at a headcount you passed two years ago. A pattern “too complex” for a team that has since doubled.
The rule: record the premise beside the verdict, and re-open the rejection when the other half of the pairing moves.
sources: concepts/a-rejection-can-outlive-its-reason