Two things stated up front.
First, in April 2026 this magazine ran a piece about a doctor building a clinic flow tool. This is not a specific practice. We constructed the shape exactly as it actually works, and we do not name where. What follows was built to that shape, and the procedure and the numbers are invented.
Second, this is not medical advice and what we built is not a medical device. This series did no clinical validation and is not in a position to. What it deals with is one software boundary — what keeping judgment outside the tool looks like in code.
A line drawn in prose gets erased
The original had that line too. "Leave the diagnosis to the person; only organise the flow of the visit onto a screen."
Correct. The problem is that it existed only as a sentence.
A line that exists as a sentence gets erased. Specifically it gets erased like this: months later somebody says "a one-line summary would be handy" and adds a field. Into that field goes a string like broadly within range. Nobody notices the moment. That is the moment the tool started diagnosing.
So this time we drew it in code. Twice.
The first line — there is no such tool
tools offered: flow.state, flow.done, readings.list
Three. Show the routine, mark one step done, return the readings as they are. There is no tool that judges, classifies or interprets.
The verification starts from the tool names.
for W in diagnos assess triage interpret advise; do
if grep -qi "tools offered:.*$W" captures/run.log; then
echo " a tool is named like it produces a judgement: $W"; exit 1
fi
done
This is an application of the principle confirmed in an earlier piece. The tool list is the surface, and a capability not on the list cannot be reached by a person pressing or a model choosing.
The second line — sound like a verdict and it throws
The list alone is not enough, because a judgement can slip inside the strings flow.state returns.
/// Words that would turn a report into a verdict. Anything this server is
/// about to say is checked against them.
///
/// A list of words is a crude guard and it is meant to be. It cannot stop a
/// determined author, but it does stop the ordinary way this line gets
/// crossed: someone adds a helpful-sounding summary field months later and
/// nobody notices that the tool started diagnosing.
static const forbidden = [
'diagnos', 'likely', 'suggests', 'consistent with', 'probable',
'abnormal', 'normal', 'healthy', 'concerning', 'severe', 'mild',
'recommend', 'should take', 'prescribe',
];
static String _guard(String s) {
final lower = s.toLowerCase();
for (final w in forbidden) {
if (lower.contains(w)) {
throw StateError('clinic_server tried to emit a judgement word: "$w"');
}
}
return s;
}
Every string this server emits passes through that function. Note that normal is on the list — the most harmless-looking word, and the one that most often crosses the line.
It is a crude guard. It will not stop somebody determined. But the way this line actually gets erased is not determination but inattention, and inattention is stopped by this much.
And the verification sweeps the whole run.
no judgement vocabulary in anything the server returned
This content requires Developer or above
Sign in and upgrade your plan to continue reading.
View Plans