Skip to content

Asking several questions at once

When several independent things need judging about one subject, given(x).ask({ ... }) asks them together. They share a request until the runtime’s batching limit is reached; each key comes back as its own Judgment.

import { chooseFrom, given, means, scale } from "jevlish";
interface Feedback {
text: string;
plan: "free" | "pro" | "team";
}
const AREAS = ["invoicing", "reports", "exports", "permissions"] as const;
const severity = scale<Feedback>("how badly the problem affects the user")
.from("An annoyance; work continues")
.through("Work continues through a workaround")
.to("The user cannot do their job");
const profile = (item: Feedback) =>
given(item)
.seenAs((f) => ({ message: f.text }))
.ask({
problem: means<Feedback>("the message describes something not working"), // Noul
request: "the user asks for a change or a new capability", // Noul, from a string
severity, // Score over three described levels
area: chooseFrom(AREAS).by("which part of the product the message is mainly about").orNone("no single area"), // Choice
paying: (f) => f.plan !== "free", // code; adds nothing to the request
});
const answers = await profile({ text: "Exports hang every Friday. We copy the data by hand.", plan: "team" });
answers.problem; // Judgment<boolean>
answers.severity; // Judgment<Measurement>
answers.area; // Judgment<"invoicing" | "reports" | "exports" | "permissions" | null>
answers.paying; // Judgment<boolean>, decided by code
answers.problem.evidence === answers.area.evidence; // every answer shares one request

Each value in the object is one of:

  • A condition: a string, a code predicate, or a meaning. Produces Judgment<boolean>. Composite meanings are fine; their semantic leaves become separate Noul questions in the same request and are combined locally.
  • A scale. Produces Judgment<Measurement>.
  • A Choice: chooseFrom(candidates).by(criterion), optionally .orNone(...). Produces Judgment<C> or Judgment<C | null>.

The result type is inferred per key, so answers.severity.value is a Measurement and answers.area.value is one of the AREAS.

A predicate in the object is evaluated locally and recorded as a code judgment. It adds nothing to the request. paying: (f) => f.plan !== "free" is there so the answer sits next to the others with the same shape, not because the model is consulted.

If every question is settled by code, no request is sent at all.

All answers from one ask share the same evidence object: the one request, every judgment, and the policy. Checking answers.problem.evidence === answers.area.evidence is true. This is what makes it possible to count intersections afterwards, as the Insights example does, knowing they came from the same look at the same message.

A runtime splits a question set into requests of at most questionsPerRequest (default 32) and caches each chunk independently. A large ask may therefore become more than one request; plan() shows how many. See Runtime.