Refused by design, the evidence edition, episode 1

Refused by design, one, the evidence edition: the sales desk that refuses

What Blackthorn's own sales desk agent will not do, written as code with a test for each refusal, and why a rule in a prompt is not a rule.

Published 2026 10 07

00The note

Blackthorn Labs is an applied research firm with a business services focus. It builds systems whose constraints are enforced in code rather than instructed, and it installs them inside operating businesses. This is the evidence edition of the first episode of Refused by design: the same stage told as engineering, with the actual refusals and the tests that prove them. The narrative episode, The wish, is beside it in the notes. The system here is the firm's own: the agent that works its sales desk.

01What the desk is

The desk agent reads the call log, drafts notes to people the firm has called, keeps the calendar, and reports the numbers that decide whether the outbound lane lives or dies. She is named Sloane, for the sloe, the fruit of the blackthorn. She never dials a phone. She sends mail only in lanes that have been ruled on, and only text that was approved word for word. Everything she is not allowed to do is a function in one file, sales/desk/gates.py, and every one of those functions has a test that feeds it the input it exists to refuse.

The file opens with the sentence that explains the whole design: a rule written in a prompt loses to a rule written in code. That was measured before it was believed. An earlier agent in the firm was given the same rule nine times as an instruction and broke it nine times under pressure. The same rule as a function has not been broken since, because it cannot be argued with. It returns a refusal, and the refusal is an object with a name, a reason in plain words, and the fix.

02The phantom dial

The headline number on a sales desk is dials placed. Every rate on the scorecard divides by it, and the kill test that decides whether the lane continues reads it. On 2026 09 20, exploratory testing found that an empty line typed into the capture box wrote a complete dial row. So did a stray keystroke, a question mark, and the words "oops wrong window". Six junk inputs moved the dial count by six, and the log is append only, so every one of them was permanent.

The fix was not a reminder to be careful. It was a gate: a capture must name the row it is about. "12 no answer" is a complete row and passes, because a dial that nobody answered is a real ending, and counting it honestly is what makes the connect rate mean anything. An unnumbered line is not a stricter version of that. It is a different thing, and it is refused.

The test for this gate, attack 19 in sales/desk/test_desk.py, feeds it the six junk lines and checks that each one is refused by name. Then it does the other half, which most tests skip: it feeds the gate four real lines, including "12 no answer" and "7 gatekeeper, call back tuesday", and checks that every one of them is written. A gate that blocked those would quietly inflate the connect rate, which is the opposite failure at the same cost. The file calls those four lines the canary. Without the canary, a count of refusals proves only that a rule can say no. It never proves that the rule lets the right things through.

03No score without evidence

A row may not carry a conclusion and no measurement. If a note says the call went well, or badly, or that the prospect was interested, and the row holds nothing a second reader could check, the evidence gate refuses it and says what to add: connected or not, length, which opener, how many questions were answered, the objection code. The conclusion words are a list in the code. The measurements that count are a list in the code. Neither list is tunable by the agent. Kyle changes the scorecard file, then the code, in that order.

04A number without its guard is not reported

The scorecard pairs every headline number with the number that keeps it honest. Dials are paired with connect rate. Connect rate is paired with conversations over two minutes. Conversations are paired with demos booked per conversation. Demos booked are paired with demos held. Demos held are paired with audits and signatures. Call length is paired with questions answered.

The guard gate makes the pairing an access control rather than advice. A metric reported without its guard is refused outright, and the refusal names the missing number. The reason is in the code's own comment: each headline number is gameable on its own. A desk that can report dials without connect rate will, in time, report a lot of dials.

05No conclusion below the minimum sample, and never pooled

The sample gate holds the minimum counts before anyone is allowed to conclude anything: forty calls before a judgment about an opener or a segment, twenty before a judgment about an objection, sixty before a judgment about a calling hour, twenty five before a judgment about price, forty before a judgment about a script. Below the line the gate refuses. Above the line it still refuses if the conclusion is about a mixed list rather than a named segment, because coverage is a property of a segment and not of a list, a lesson the firm paid for once and wrote down as a rule.

06Nothing leaves in prose that the facts table does not support

The claim gate reads every sentence that would leave the building and asks whether the facts on file support it. One of its rules is specific and came from a real failure: no sentence may put the firm's own phone line next to a predicate meaning it can be reached. The first version of that rule was seven phrasings learned one at a time in a single day, and the model that drafted the sentences did not use the phrasings on the list. The second version is a rule about meaning, measured against the live call card, and it caught everything the patterns caught and two more they missed. The patterns stayed underneath it as a backstop, because a generalising rule that is wrong in a new way should not be the only thing between a draft and a stranger.

07Nothing is sent without approval of that exact text

The send gate has two conditions and both are plain. First, commercial email needs a physical mailing address in the footer, and the address on file must be marked confirmed by the person who has the right to use it. If it is not, nothing sends. Second, the text that leaves must be the text that was approved, character for character. An approved draft that was edited afterwards is refused as unapproved, because approval of a sentence is not approval of a different sentence.

08Money is a fact about an invoice, not a fact about a person

Two gates sit around payment. The first refuses payment data outright: card numbers, bank numbers and government identifiers may not reach any surface the agent reads or writes, because the firm's own policy forbids the repository from holding them at all. The second refuses a kind of sentence. If the agent is about to state a judgment about anyone's ability or willingness to pay, the gate stops it, and the reason is written where the next engineer will read it: a missed debit is a fact about an invoice, not a fact about a person, and a sales agent that forms the second kind of fact will eventually say it out loud. The fix is one line. Report what the invoice says and stop there.

09How the proof is built

The test file announces each attack by name and feeds the gate the bad input first, then the good input the gate must still allow. On the day this note was published the whole file ran green, every attack refused and every canary written. The count of its checks is not typed anywhere in the firm's copy. It lives in an evidence registry as an entry that holds the command which produces it, and the firm's internal pages render it from there; once a week has passed since the last run, those pages refuse to build until the suite runs again. A typed number is a measurement frozen at the moment somebody typed it. The firm found two of its own numbers stale that way on 2026 09 23 and wrote the registry the same day.

Two of the attacks in that file were written after real defects, and both defects are recorded in the comments of the code they broke. That is the other half of the design: a refusal is not finished when it works. It is finished when the way it was once wrong is written next to it.

10What this means if you run an office

The pattern transfers to any system that is allowed to act on your behalf. Decide what it must never do. Write each of those as a function that returns a refusal with a reason and a fix, not as a sentence in its instructions. Give each function a test that feeds it the bad input, and a second test that feeds it the good input it must still allow. Pair every number it reports with the number that keeps the first one honest. Then let the system run, because the rules no longer depend on it remembering them.

If you want a first read of where that pattern would sit in your own office, the firm offers a thirty minute call. No charge, no pitch. You leave with a first read and a plain next step.

11All notes