Feature: Krank Rules Engine
Purpose
A human writes intent in prose. A model translates the prose into a rule set, which a small deterministic interpreter evaluates against facts. A renderer translates the rule set back into prose so the translation can be checked against the original intent.
Requirements
KRANK-R001— A rule set must be a JSON document with afactsarray and arulesarray.KRANK-R002— A rule must have a non-empty stringid, awhenarray of conditions, and athenarray of actions.KRANK-R003— A condition must be{"fact": PATTERN},{"fact": PATTERN, "not": true}, or{"count": {"fact": PATTERN, "at_least"|"at_most": N}}, where a pattern value is a scalar (equality), a$variable(binding), or an operator object.KRANK-R004— An action must be one ofassert,retract, oremit.KRANK-R005— The interpreter must fire rules forward in document order until no unfired rule binding remains, and a rule binding must fire at most once.KRANK-R006— The interpreter must refuse a malformed rule (a missing id, an action that is none ofassert,retract,emit, or an action with more than one of those keys).KRANK-R007— The renderer must translate a rule set into deterministic prose, so the same rule set always renders to the same text.KRANK-R008— The command-line tool must run or render a rule set from a file without prompting, and fail closed on a missing file or invalid JSON.KRANK-R009— A$variablein a pattern must bind the matched fact’s value, left to right; two conditions that name the same variable must agree.KRANK-R010— An operator object must hold every one of its operators, drawn fromeq,ne,lt,lte,gt,gte,in, andprefix.KRANK-R011— A$variablein an action must be replaced by its bound value, in anassertorretractfact and in any leaf of anemitvalue.KRANK-R012— The interpreter must refuse a rule that uses an unbound variable, and a negated condition that would bind a new variable.KRANK-R013— A rule may carry an optional finite numericpriority; a higher priority fires first, and equal priorities keep document order.KRANK-R014— A session must keep facts and refraction acrossruncalls, and exposeassert,retract,facts,emitted,trace,reset, andforget_refraction.KRANK-R015— A condition naming a literaltypemust match only facts of that type, while a$variableor an operator ontypemust scan every fact.KRANK-R016— The command-line tool must offercheck <ruleset.json> [facts.json] [--fail-on-emit]: it runs the rule set against the supplied facts, prints the firings and emissions, and exits nonzero on any emission when--fail-on-emitis set, so a caller can gate on the engine’s decision.KRANK-R017— A count condition holds when the number of facts matching its pattern is withinat_leastandat_most; its pattern may reference bound variables but may not bind a new one, and a count without either bound is invalid.
Behavior
- Running the engine returns the final facts, the emitted values, and the firings.
- Rendering a rule set produces readable prose a reviewer can compare to the original intent.
- Assert of an equal fact is a no-op; retract removes every matching fact.
Dependencies
- None.