Policy
Defined in: src/policy.ts:31
Ordered clauses that turn answers into an outcome. Clauses are checked in
order and the first active one wins; a numeric clause with exit below
enter holds its outcome until the value drops below exit (hysteresis).
Every method returns a new policy; O accumulates the outcomes declared so far.
A huncho builds one of these behind .when() and .else(). Use policy()
directly to decide over answers you already have, as replay does.
Example
Section titled “Example”import { policy, type Policy } from "huncho";
type Signals = { urgency: number; billing: boolean };
const route: Policy<Signals, "page" | "billing" | "triage"> = policy<Signals>("support.route") .when((a) => a.urgency, { enter: 0.8, exit: 0.6 }, "page") .when((a) => a.billing, "billing") .else("triage");
route.decide({ urgency: 0.7, billing: false }); // "triage"route.decide({ urgency: 0.7, billing: false }, "page"); // "page": held, 0.7 is above exitType Parameters
Section titled “Type Parameters”A
The answers a clause reads.
O extends string = never
The union of outcomes declared so far.
Methods
Section titled “Methods”decide()
Section titled “decide()”decide(
answers,previous?):O
Defined in: src/policy.ts:115
The outcome for these answers. Pure: pass previous, the outcome this key
got last time, and hysteresis applies; omit it and every clause starts cold.
Parameters
Section titled “Parameters”answers
Section titled “answers”A
What the clauses read.
previous?
Section titled “previous?”string
The outcome held for this key, if any.
Returns
Section titled “Returns”O
Throws
Section titled “Throws”PolicyError when no clause is active and there is no else.
Example
Section titled “Example”import { policy } from "huncho";
const gate = policy<{ p: number }>("gate").when((a) => a.p, { enter: 0.8, exit: 0.6 }, "open").else("closed");
let held = gate.decide({ p: 0.9 }); // "open"held = gate.decide({ p: 0.7 }, held); // "open"held = gate.decide({ p: 0.5 }, held); // "closed"else()
Section titled “else()”else<
T>(outcome):Policy<A,O|T>
Defined in: src/policy.ts:96
The outcome when no clause is active. Without one, decide throws when
nothing matches.
Type Parameters
Section titled “Type Parameters”T extends string
Parameters
Section titled “Parameters”outcome
Section titled “outcome”T
Returns
Section titled “Returns”Policy<A, O | T>
Example
Section titled “Example”import { policy } from "huncho";
const gate = policy<{ p: number }>("gate").when((a) => a.p, { enter: 0.8 }, "open").else("closed");gate.decide({ p: 0.1 }); // "closed"when()
Section titled “when()”Call Signature
Section titled “Call Signature”when<
T>(test,outcome,options?):Policy<A,O|T>
Defined in: src/policy.ts:52
A boolean clause: active when test is true. With exit, an outcome this
clause produced last time is held while exit stays true, even if test
has gone false.
Type Parameters
Section titled “Type Parameters”T extends string
Parameters
Section titled “Parameters”(answers) => boolean
Reads the answers; true enters the outcome.
outcome
Section titled “outcome”T
What decide returns while this clause is active.
options?
Section titled “options?”exit keeps a held outcome; omit it and the hold ends as soon as test is false.
(answers) => boolean
Returns
Section titled “Returns”Policy<A, O | T>
Example
Section titled “Example”import { policy } from "huncho";
const gate = policy<{ p: number }>("gate") .when((a) => a.p >= 0.8, "open", { exit: (a) => a.p >= 0.6 }) .else("closed");
gate.decide({ p: 0.7 }); // "closed"gate.decide({ p: 0.7 }, "open"); // "open": held, exit still trueCall Signature
Section titled “Call Signature”when<
T>(select,thresholds,outcome):Policy<A,O|T>
Defined in: src/policy.ts:79
A numeric clause: active when select is at least enter, and held while
it is at least exit for a key that produced this outcome last time. exit
defaults to enter, which is no hysteresis.
Type Parameters
Section titled “Type Parameters”T extends string
Parameters
Section titled “Parameters”select
Section titled “select”(answers) => number
Reads a number from the answers, usually a probability.
thresholds
Section titled “thresholds”enter and exit must be finite with exit at most enter.
number
number
outcome
Section titled “outcome”T
What decide returns while this clause is active.
Returns
Section titled “Returns”Policy<A, O | T>
Throws
Section titled “Throws”ConfigError when a threshold is not finite or exit is above enter.
Example
Section titled “Example”import { policy } from "huncho";
const gate = policy<{ p: number }>("gate") .when((a) => a.p, { enter: 0.8, exit: 0.6 }, "open") .else("closed");
gate.decide({ p: 0.85 }); // "open"gate.decide({ p: 0.7 }, "open"); // "open": heldgate.decide({ p: 0.5 }, "open"); // "closed": below exitwith()
Section titled “with()”with(
overrides):Policy<A,O>
Defined in: src/policy.ts:133
A copy with different thresholds on numeric clauses, keyed by outcome.
Boolean clauses and the else are unchanged. Override enter alone on a
clause without hysteresis and exit follows it.
Parameters
Section titled “Parameters”overrides
Section titled “overrides”{ readonly [K in string]?: { enter?: number; exit?: number } }
Returns
Section titled “Returns”Policy<A, O>
Throws
Section titled “Throws”ConfigError when a resulting threshold is not finite or exit is above enter.
Example
Section titled “Example”import { policy } from "huncho";
const gate = policy<{ p: number }>("gate").when((a) => a.p, { enter: 0.8, exit: 0.6 }, "open").else("closed");const stricter = gate.with({ open: { enter: 0.9, exit: 0.7 } });
gate.decide({ p: 0.85 }); // "open"stricter.decide({ p: 0.85 }); // "closed"