Skip to content
Product Strategy

Refusal Logs as a Product Roadmap

Updated

Knowledge on this page was mainly distilled from Malleable Software Needs a Kernel You Can Still Change.

In a malleable product built on a kernel grammar, a refusal is not a dead end. It should be the most valuable event in the system. When the model composing on a customer's behalf cannot express a request in the vendor's published words, the structured refusal is richer product research than any feature request. The ambiguity is already gone. The customer did not describe a wish in product language and leave you to interpret it. They tried to say something exact, in your words, and your words ran out.

Why there is a refusal to record at all

A kernel grammar is a fixed list of words naming the kernel's primitives, plus rules for combining them. Customers ask in their own words, a model translates the request into a sentence in the grammar, and the system checks it. The system then either stores the sentence or refuses with a reason. Without such a grammar there is usually nothing to record. Nothing refuses, because nothing was ever said in terms the system could check. The request dissolves in a conversation with an assistant and reaches the vendor, if it reaches them at all, as a paraphrase in a support ticket.

Access refusals and product refusals

Two kinds of failure hide behind the word refusal. An access refusal is about the person: this user may not read that column. Every product already has access control, and the fix is to ask an administrator. A product refusal is about the product: there is no way to say this at all, and nobody's permissions would change that. Only the second kind tells you what to build next, and it is the kind most systems never record.

What each product refusal yields

  • Near misses. The word exists but does not apply. Someone asked to shade a view by a field that has no shade rule, or to group by a column that cannot group. The failure is made entirely of words you already own, so what you collect is a count over a fixed list.
  • No word at all. Someone wanted a rolling median and the grammar has never heard of one. Nothing on the list was reached for, so a count records nothing. Instead the model describes what it could not express: an operation that turns a series of numbers into one number over a moving window. That is the gap, described in your own types.

Either way the input is your own word list plus a description of what was missing, so none of it has to touch what customers are actually doing. It also does not have to be a quarterly report. A model can sit on the stream permanently, tracking which words get used, which get reached for and are not there, and which have quietly stopped being used.

The model proposes, a person decides

The model clusters refusals and names the primitive that would clear the most of them. It should not add that primitive. Every published word is a promise to keep that word working forever, and accepting the promise is a decision with somebody's name on it. The payoff is that the next platform version stops being a guess assembled from interviews and win/loss calls. It becomes an ordered list: which primitive is missing, and how many times somebody hit the wall where it should have been. Ten thousand dead ends turn into product research nobody had to schedule.

The answer to being out of luck

Ink & Switch's honest complaint about plugin surfaces is that when no surface exists for the customization a user wants, that user is simply out of luck. A fixed word list fails in the same shape. The customer who hit the wall is still stuck this quarter, but not structurally, because their failure is the input that grows the grammar. Without the refusal log, a bounded grammar is only a cage.

The permanent blind spot

The log only hears from people who tried to say something. Someone who opens the product, cannot imagine a sentence worth attempting, and closes it again never generates a refusal. No signal built from usage can find that person, because there is no usage, the refusal log included.

Q&A

Why not let the model publish the missing word automatically?

Because publishing a word is a promise to keep it working forever. The model is well suited to clustering refusals and naming the primitive that would clear the most of them, but accepting a permanent commitment is a decision that needs somebody's name on it. The model proposes; a named person decides.

Should access refusals feed the product roadmap?

No. An access refusal means a particular user lacks permission, such as reading a restricted column, and the fix is to ask an administrator. It says nothing about missing capability in the product. Only product refusals, where no one's permissions would make the request expressible, indicate what to build next.

Does logging refusals mean collecting what customers are doing?

It does not have to. A near miss is recorded as a count over the vendor's own fixed word list, and a no-word refusal is recorded as the model's description of the missing operation in the vendor's own types. Neither requires capturing the customer's underlying data or activity.

Does the refusal log help the customer who hit the wall right away?

Not immediately. That customer is still stuck this quarter. The difference is that they are not stuck structurally: their refusal becomes input that can justify adding a new primitive, so the bounded grammar can grow toward what people actually tried to say.

Who will a refusal log never hear from?

People who never attempt a sentence. A user who opens the product, cannot imagine anything worth asking for, and leaves generates no refusal. Because the log is built from usage, it is permanently blind to users who produce no usage at all.