jevbooks

← All design patterns

Questionnaire

Flat fan-out · 问卷

One thing per question, all at once

Split one judgment into small questions that do not depend on each other, and ask them all in a single request.

statenoulchoicescorenoul

The problem

You are building a prose checker. A paragraph goes out with one question attached: does this read like it was written by a machine?

A paragraph with one obvious tell and four decent sentences comes back at 0.52. The impression got averaged out — one fifth of the paragraph is wrong, so you get one fifth of a score. But what you needed to know was "there is one thing here to fix", not "this paragraph is a 5 out of 10".

So you rewrite it as five specific faults, each judged sentence by sentence. Someone measured exactly this change: of 80 planted faults, the catch went from 58 to 63, with no new false alarms. Then the next problem arrives: five questions written as five separate calls, 300 ms each, means a paragraph waits a second and a half — and ten rules means three seconds.

The solution

The Questionnaire pattern says: one question asks about one thing, and all of the questions go out against the same material in one request.

One thing means asking whether something is there. "Does this paragraph contain a sentence of the form not X, but Y?" can be answered; "is this paragraph well written?" cannot. One sentence is enough to trip it, and the good sentences around it do not excuse it.

Each answer gets its own line and is consumed on its own: abuse over 0.8 blocks, urgent over 0.7 pages a human, the rest routes by category. What you must not do is ask the same thing three ways — three synonyms are not three pieces of evidence, they are one number times three.

Ask · Answer · Act

  1. AskPut in one message from a user and ask three things at once: does this need a human within the hour, is it about a charge, does it contain abuse.
  2. AnswerAbuse 0.05, urgent 0.81, billing 0.63.
  3. ActNo abuse, and urgent is over its line, so a human is paged and the billing answer is not needed this time.

Where the name comes from

A questionnaire. A doctor does not ask "are you healthy?" — the form goes item by item: where does it hurt, for how many days, any fever. Each item can actually be answered, and the diagnosis is what you make of them together. And the form is handed to you all at once, not one question at a time with a wait in between.

Use it when

What you need to know splits into a few things that can each be answered on their own.

Not when

The wording of the second question depends on the answer to the first — then either merge them or use Prefetch. Or several of your questions are the same sentence in different clothes.

Projects that do this

  • foreman — Agent supervisor and software factory foreman using decision models.
  • jev-axi — CLI for TypeSafe's Jev: fast calibrated judgments from the shell.
  • snifftest — Prose linter that flags AI writing tells with countable rules and one judgment model.

All projects with this pattern →

Read this code
Show me the code
const { answers } = await jev(state, {
  urgent:  noul("Does this need a human within the hour?"),
  billing: noul("Is this about a charge or a refund?"),
  abusive: noul("Does the message contain threats or slurs?"),
});
// three probabilities, one round trip, about 300 ms; each has its own line
if (answers.abusive.p >= 0.8) return block();
if (answers.urgent.p >= 0.7)  return page();
return answers.billing.p >= 0.6 ? route("billing") : route("general");
How jevbooks recognises it

How do we know a project does this? We put one question about its README to Jev and it returns a percentage; the higher, the more it looks like it. If you copy the question, copy one thing: ask whether the text mentions this one concrete thing, never whether the project is good.

questions.json · sent for every README
{
  "flat-fanout": {
    "type": "noul",
    "instructions": {
      "what": "Does the text describe sending several independent questions about the same state in a single Jev request?",
      "not_for": "One question per request, or questions spread over separate calls."
    },
    "criteria": {
      "true": "The text explicitly describes this. One sentence is enough; other content does not cancel it.",
      "false": "The text does not describe this."
    }
  }
}

Build this with Jev →