Meanings
A meaning is a proposition the model judges about a subject: named, composable, inspectable, and graded against fixtures like any other function. A string in a condition is a meaning without a name. means(...) gives it one, and a boundary.
Defining one
Section titled “Defining one”import { means } from "jevlish";import type { Ticket } from "./support.js";
export const blocked = means<Ticket>("the customer is currently unable to complete their task") // Inside the boundary: what the proposition covers. Becomes Noul criteria.true. .including("a product failure prevents them from completing the task") // Outside the boundary: what it does not cover, even when it looks close. Becomes criteria.false. .excluding("they can complete the task despite inconvenience, or they are only asking a question") // A name for traces, fixtures, and error messages. .named("blocked");means<T>(proposition)states what is being judged.Tis the subject type; it keeps aMeaning<Ticket>from being used on anEngineer..including(text)draws the boundary from the inside: cases the proposition covers even when they look marginal. It becomes the Noul’scriteria.true..excluding(text)draws it from the outside: cases the proposition does not cover even when they look close. It becomescriteria.false..named(name)labels the meaning in traces, plans, fixtures, and error messages.
including and excluding apply to a single proposition. They throw on a composite, because there is no one Noul to attach the boundary to.
import { blocked, saysResolved } from "./vocabulary.js";
// including() and excluding() apply to a single proposition.// Draw the boundary on each means() first, then compose.const composite = blocked.unless(saysResolved);
try { composite.excluding("the outage was announced in advance");} catch (error) { error; // SenseError: .excluding() applies to a single proposition; (...) is a composite.}Composing
Section titled “Composing”.and(), .or(), .unless(), and .not() combine meanings with strings, code predicates, and other meanings. The result is an expression tree. The propositions are never rewritten or joined into a longer sentence; each semantic leaf becomes its own Noul question, each code leaf runs locally, and the answers are combined with three-valued logic.
import { all, any, means, not } from "jevlish";import type { Ticket } from "./support.js";import { blocked, saysResolved, threatensToLeave } from "./vocabulary.js";
const isOpen = (t: Ticket) => t.status === "open";
// Composition keeps nodes; it never rewrites the propositions.export const needsAttention = blocked.unless(saysResolved).or(threatensToLeave).and(isOpen);
needsAttention.describe();// (((blocked: "..." and not saysResolved: "...") or threatensToLeave: "...") and isOpen())
// The same shapes as functions, for when you start from strings or predicates.export const escalatable = all("the customer reports a failure", isOpen, not(saysResolved));export const noteworthy = any(blocked, threatensToLeave, means<Ticket>("the customer mentions a competitor"));The shape matters. blocked.unless(saysResolved).or(threatensToLeave) qualifies only the blocked branch with the resolution check, so a churn threat escalates regardless. Writing it as one sentence would leave that to the model.
Within one subject, identical semantic leaves are deduplicated by their instructions and criteria. Reusing the same meaning in two branches therefore does not ask the same Noul twice.
all(...), any(...), and not(...) are the same operations as functions, for when you start from strings or predicates rather than a meaning.
Inspecting
Section titled “Inspecting”.describe() renders the tree as text, with names where you gave them; query plan() notes use this representation. .toJSON() serializes the tree for your own logs or tooling, reducing code predicates to their names.
Grading
Section titled “Grading”Because a meaning is a value, it can be tested. grade(meaning, fixtures) runs it against labeled examples and reports accuracy, coverage, and abstentions. See Testing.