Changelog
All notable changes are recorded here. The format follows Keep a Changelog and the project uses Semantic Versioning.
All notable changes are recorded here. The format follows Keep a Changelog and the project uses Semantic Versioning.
[Unreleased]
Changed
- Rule Cascade has its own domain: https://rulescascade.com. The documentation, the downloads,
install.shandinstall.ps1are served there;rules.sdods.comredirects every path to the same path on the new domain, so existing links and scripts keep working. - The Go module is
rulescascade.com/go(go install rulescascade.com/go/cmd/rcas@latest). Versions up to 1.0.0-alpha.5 remain available asrules.sdods.com/go; to move, replace the import path and require 1.0.0-alpha.6 or later. - The schema
$idishttps://rulescascade.com/schema/v1/rule-cascade.schema.json. The old address redirects to it. - Java coordinates. The Java runtime is
com.rulescascade:rules-cascade-coreand its package iscom.rulescascade(wascom.sdods.rules:rules-cascade-core,com.sdods.rules.cascade). It had not been published to Maven Central under the old name. - The site tells search engines that rulescascade.com is the canonical address (canonical links,
sitemap.xml,robots.txt).
[1.0.0-alpha.5] - 2026-10-06
Added
- Java on Maven Central:
com.sdods.rules:rules-cascade-core, signed with the release keyEA4FA781CD906ED62FB1C8341C70DE86DB43612C. - Signed downloads on the site:
rules.sdods.com/download/,install.shandinstall.ps1serve the signedrcasfiles, starting with 1.0.0-alpha.4.
Fixed
npm ciin a checkout: the repository no longer declares the@rules-cascade/cli-*platform packages; the release adds them to the published@rules-cascade/cliat its exact version.
[1.0.0-alpha.4] - 2026-10-06
Changed
- Java coordinates. The Java runtime is
com.sdods.rules:rules-cascade-coreand its package iscom.sdods.rules.cascade(wasio.github.yarlisaisolutions:rule-cascade-core,io.github.yarlisaisolutions.rulecascade). It had not been published to Maven Central under the old name.
Fixed
npx -y @rules-cascade/cli <command>runsrcas. In 1.0.0-alpha.3 the package declared two commands, and npx could not tell which to run, so MCP configurations that start the server with npx failed. The npm package now providesrcasonly; the install scripts andgo installstill providerule-cascade.
[1.0.0-alpha.3] - 2026-10-06
Added
rcas, the Rule Cascade command (it replacesrule-cascade, which stays as an alias):initscaffolds a project (rcas.yaml, a first ruleset with golden tests, CI, a loading guide per language);checkandtestread the project's rules;compile --all;analyzeinventories API schemas and validation code in an existing code base;derivebuilds baseline rulesets from OpenAPI or JSON Schema (a Go port, byte-identical to the reference);proposalsreviews what an agent proposed;doctor; shellcompletion.- AI coding tools.
rcas mcpis a Model Context Protocol server whose only write is a proposal under.rcas/proposals/;rcas mcp installregisters it with Claude Code, Codex, Cursor, Windsurf, Gemini CLI and VS Code;rcas agent installwrites AGENTS.md, CLAUDE.md, GEMINI.md, Copilot and Cursor rules, Claude sub-agents and a skill. - Distribution. npm
@rules-cascade/cli(with one package per platform), the install scriptshttps://rules.sdods.com/install.shandinstall.ps1, andgo install rules.sdods.com/go/cmd/rcas@latest.
Changed
- The Go module is
rules.sdods.com/go, published from the public mirrorYarlisAISolutions/rule-cascade-go. The source repository is private; the packages stay free under the Apache License 2.0. - Release files are named
rcas-<os>-<arch>andrcas.wasm. - The schema
$idishttps://rules.sdods.com/schema/v1/rule-cascade.schema.json.
[1.0.0-alpha.2] - 2026-10-05
The project is now called Rule Cascade. A ruleset is compiled once into a JSON bundle and evaluated identically by Python, TypeScript, Java and Go, by a single-file command for Linux, macOS and Windows, and by a WebAssembly module. The conformance suite has 1899 cases.
Licence
- Free packages under the Apache License 2.0, Copyright (c) 2026 Yarlis LLC; it replaces the MIT
License chosen earlier in this version.
LICENSEandNOTICEare in every package (npm, PyPI, the Maven jar underMETA-INF, the Go module), and every manifest declaresApache-2.0. The source repository is private: the manifests point at https://rules.sdods.com instead of a repository, vulnerabilities are reported to support@sdods.com, and the Go module is published from a public mirror asrules.sdods.com/go. - Packages on the public registries. After the signed release, a tag
v<version>onmainruns the whole CI suite and then publishes to npm and PyPI with trusted publishing, to Maven Central (signed, with sources and javadoc; off until enabled), tags the Go module and pushes a multi-platform server image with a provenance attestation to GHCR. npm packages now publish to npmjs.com instead of GitHub Packages. Seedocs/releasing.md.
Breaking
-
The npm packages moved to the
@rules-cascadescope and split in four. Nothing had been published under the old names.@yarlisaisolutions/rule-cascadeis now:@rules-cascade/common: the rule, bundle and manifest types, the cron schedule (@rules-cascade/common/cron) andVERSION. No dependencies.@rules-cascade/core: evaluation and compilation,@rules-cascade/core/loader, and therule-cascade-nodecommand. It re-exports everything in common, so type imports keep working.@rules-cascade/client:createManifestClientandlocalStorageAdapter(moved from core), and the React hook at@rules-cascade/client/react(was@yarlisaisolutions/rule-cascade/react).
@yarlisaisolutions/rule-cascade-serveris now@rules-cascade/server. The release publishes them in that order. Java, Python and the server image keep their names. The schema$idis nowhttps://rules.sdods.com/schema/v1/rule-cascade.schema.json, where the site serves it. -
Name. Rule Contract became Rule Cascade. The document key is
ruleCascade(wasruleContract), the schema isspec/v1/rule-cascade.schema.json, the OpenAPI extension isx-rule-cascade, the npm packages are@rules-cascade/common,core,clientandserver(see the npm entry above), the Maven artifact isrule-cascade-coreand the Java package isio.github.yarlisaisolutions.rulecascade. -
Specification: checksums. The resolved ruleset has the new members
types,functionsandoperatorsand the renamed key, so the checksum of every ruleset changes. -
Specification: findings.
finding.componentis replaced byfinding.location, an object with thepage,screen,sectionandcomponentthe rule's target names. -
Specification: patterns.
matchesaccepts only the portable subset of section 4.4.\sand\b, which alpha.1 allowed, are rejected;.matches line breaks;$is the very end of the string; counts, nested counts multiplied and the pattern length are limited to 1000. -
Specification: numbers. A JSON number is the IEEE 754 double nearest to what was written, in every runtime. Every number leaving the engine is rounded to 15 significant digits, whether it was computed or passed through. A number beyond the range of a double is refused on the way in and is an evaluation error on the way out.
-
Specification: strictness. An object that is not exactly
{var},{op, args}or{fn, args}is not an expression; an unknown root isnull; list indexes are runs of ASCII digits. Dates are written with ASCII digits and nothing after the value, offsets go up to23:59, and the UTC date lies in the years 0001 to 9999.lowerchanges only the ASCII letters. -
Specification: evaluation. A state rule applies all of its effects or none. An evaluation request is shape-checked and refused before anything is evaluated.
-
Specification: YAML. A ruleset in YAML is read by the YAML 1.2 core schema: unquoted
no,onand2026-10-03are strings. Scalars that YAML 1.1 and 1.2 read differently must be quoted. -
Tools.
rulecheck exportandrulecheck corpusare replaced byrulecheck sync.tools/rulecheck.pyis no longer the reference implementation; it is the command-line front end ofpackages/python. -
Rule server: a token is required (breaking for deployers). The server refuses to start without
RULE_SERVER_TOKEN: it logs afatalline and exits 1 before loading any rules. SetRULE_SERVER_ALLOW_OPEN=1to serve every endpoint without a token, on a private network only. Embedded,createRuleServerthrows unless it is giventokenorallowOpen: true. The Kubernetes deployment no longer marks the token Secret optional. -
Specification: patterns. A group that repeats must not contain an unbounded quantifier (
(a+)+,(a*){2,}): such a pattern backtracks exponentially and is refused withPATTERN_NOT_PORTABLE.matchesrefuses a subject longer than 10000 code points with an evaluation error. -
Specification: nesting depth. An evaluation request whose
data,original,actororctxis nested more than 64 deep (also every root ofenvin theexpressioncommand) is refused withBAD_REQUESTbefore anything is evaluated, and a rule expression or function body nested more than 128 deep fails the load withEXPRESSION_TOO_DEEP. Depth is checked before recursing, so no runtime can overflow its stack. -
TypeScript compiler. Schema validation stops at the first problem (Ajv
allErrors: false): reporting every problem took time exponential in expression depth.compilenow reports the first schema problem only.
Added
- Specification: locale fallback. A message is read from the catalog of the requested locale,
then from each shorter prefix of the tag (
fr-CA,fr), then from the default locale. - Specification: one manifest on its own. Every runtime reads a single manifest
(
RuleSet.from_manifest,fromManifest,FromManifest), which is how a native front end receives rules. In the engine protocolloadaccepts amanifest, reportschannelsandmissingOperators, and a channel the ruleset lacks isCHANNEL_UNAVAILABLE. - Runtimes: start-up check for custom operators. Each runtime reports the custom operators a ruleset needs that the host has not registered.
- TypeScript: the manifest client keeps working through an outage of the manifest endpoint by returning the cached manifest and reporting that it is stale.
- Catalog: a server rule protects the credit limit. The read-only state guides the UI; the new validation rule is what stops the change.
- Specification: targets. A rule may target a
page,screenandsectionin addition to a component and fields, or a semantic datatype. Types are declared undertypesand bound to fields inentities.<Name>.fieldTypes; a rule on a type runs once per bound field withvalueandfieldin scope. A request may carry aviewthat narrows the evaluation to one place. - Specification: functions and custom operators.
functionsdeclares reusable expressions, called with{fn, args}, with lexical scope and no recursion.operatorsdeclaresx-*operators that the host supplies; an operator that is missing or fails makes the rule fail closed. - Specification: operators. Fifteen core operators:
between,mod,abs,min,max,round,upper,trim,concat,substring,text,map,filter,typeOfandyearsBetween. The core profile now has 45. - Specification: bundles. A bundle holds the server and the client manifest of a compiled
ruleset (section 7). Manifests gained
fieldTypes,functionsandoperators. There are two conformance levels: evaluator and compiler (section 11). - Specification: engine protocol. JSON Lines on standard input and output with the commands
version,load,manifest,evaluate,expressionandcompile(section 13). - Specification: authoring in YAML (section 12) and the load codes
TYPE_UNKNOWN,SCOPE_INVALID,FUNCTION_UNKNOWN,FUNCTION_ARITY,FUNCTION_RECURSIVE,FUNCTION_REDEFINED,OPERATOR_UNDECLARED,FIELD_TYPE_REBOUND,BUNDLE_UNSUPPORTEDandBUNDLE_INVALID. The recommended scope levels gainedprojectandmodule. - Evaluation API.
GET /rulesets/{rulesetId}/bundle;viewin the request andlocationin a finding; theBundleandViewschemas. The API description is version 1.1.0. - Conformance. 499 expression cases (were 147), 191 load-error cases (84), five fixtures with 66
golden tests (two with 17), a 1000-case evaluation corpus (300), the five published bundles, and
88 engine-protocol cases. Two rulesets exist only for the suite: conflicts, ordering and failing
closed. Three conformance operators (
x-test-reverse,x-test-sum,x-luhn) test the custom-operator mechanism. - Python.
packages/python, therule_cascadepackage: the reference implementation as an installable library, withload,RuleSet.from_bundle,evaluate,evaluate_expressionand the engine protocol (python -m rule_cascade engine). - TypeScript. Bundles (
RuleSet.fromBundle,bundle()), custom operators,viewandfinding.location,requestProblemandRequestError,missingOperators,patternProblem,jsonFinite, theEngineclass and therule-cascade-node enginecommand. - Java. Bundles (
RuleSet.fromBundle,bundle()),CustomOperator,withOperatorsandrequiredOperators,View, and the engine protocol (Engine,Main engine). The schema validator interprets the embedded schema file instead of mirroring it. - Go. A new runtime, package
rulecascade, at both conformance levels, with no dependencies outside the standard library. - Command.
rule-cascade, built from the Go runtime:version,check,compile,manifest,evaluateandengine.packages/go/scripts/build-all.shbuilds static binaries for Linux, macOS and Windows on amd64 and arm64, with checksums. - WebAssembly. The same command as a WASI preview 1 module,
rule-cascade.wasm, andpackages/go/wasi/run.mjsto run it under Node.js. - Rule server. Serves bundles (
GET /rulesets/{id}/bundle, behind the token) and loads precompiled*.bundle.jsonfiles next to source rulesets.createRuleServertakes custom operators and reports the missing ones; the command logs them at start-up and after a reload. - Tools.
rulecheck compilewrites a bundle.rulecheck conformance --engine "<command>"certifies any engine over the engine protocol.rulecheck sync [--check]regenerates the schema copies, fixtures, bundles, expectations, the evaluation corpus and the example client manifest.rulecheck checkreportsYAML_NOT_PORTABLEandNUMBER_NOT_PORTABLE. - Tools: JSON Logic.
rulecheck jsonlogic import|exportconverts expressions in both directions and refuses what it cannot convert faithfully (docs/json-logic.md). - Tools: OpenAPI.
rulecheck deriveturns the constraints of an OpenAPI component schema into a baseline ruleset with stable finding codes (docs/openapi.md). - Examples. A rule catalog by data type and severity (
examples/catalog, 34 rules, 25 golden tests); two derived rulesets with their tests (examples/derived); the same two evaluations from Python, Node.js, Ruby, PHP, Java, shell, Rust, C# and PowerShell over the engine protocol, and in process with the WebAssembly module from Node.js and Python (examples/engine-clients). The Spring Boot example can start from a bundle and registers a custom operator. - Bindings. The rule-draft response format lists the 45 core operators, function calls, places
and types; the
evaluate_rulestool accepts aview.bindings/README.mdexplains both files. - CI. Every runtime is built and certified on Linux, Windows and macOS, in process and over the
engine protocol. A job cross-compiles the command, certifies the WebAssembly module, runs the
engine clients and uploads the binaries. The tools have unit tests (
tools/tests). - Documentation.
docs/authoring-guidelines.md, ADRs 0005 to 0009,packages/python/README.md. - Examples: services, batch and agents.
examples/backend-node(node:http) andexamples/backend-go(net/http) enforce the payments contract the way the Spring Boot example does: evaluate, refuse with422problem details, persist, run commands once per idempotency key, and serve the client manifest with anETag.examples/batchstreams a CSV or JSON Lines file through any engine over the engine protocol, one decision per line.examples/agent-toolsruns the tools ofbindings/llm-tools.jsonagainst the rule server, with the actor taken from the session; its README maps the same tools onto MCP. - Tests. The React hook and the manifest client of the TypeScript runtime have their own tests.
The container smoke test (
packages/server/test/smoke-image.sh) also checks that the image fails closed without a token, that a broken reload is refused while the previous rules keep serving, and thatSIGTERMdrains. - Cross-runtime version check.
tools/check_versions.py(run bymake contractand the CIcontractjob) fails unless every runtime declares the same version: the TypeScript and serverpackage.json, the Javapom.xml, Go'sversion.go, and Python'spyproject.tomland__init__.py(PEP 4401.0.0a2is read as1.0.0-alpha.2). - CI. One job per new example on Linux, and a job that runs the Go runtime and the Go example on
Go 1.22, the minimum
go.moddeclares, withGOTOOLCHAIN=localso no newer toolchain is used. - Rule server: scheduled refresh.
RULES_REFRESH=interval(RULES_REFRESH_INTERVAL, at least 1s) orcron(RULES_REFRESH_CRON,RULES_REFRESH_TZ, default UTC) checks the rules directory on a schedule and reloads, with the safety ofSIGHUP, only when a file changed. The default,manual, is the previous behaviour. Content that was refused is not retried until it changes. - Rule server: cache policy. An optional
cache-policy.yamlin the rules directory sets theCache-Controlof client manifests per ruleset:revalidate(default, unchanged),ttl(withstale-while-revalidateandstale-if-error) orpermanent. A bad policy file is refused like a bad ruleset.?checksum=on the manifest URL answersimmutableinpermanentmode, and409withno-storewhen it is not the checksum being served (a server extension, not in the OpenAPI description). Server manifests and bundles stayprivate, no-cache. - Rule server: worker threads.
RULE_SERVER_WORKERS(default 0) evaluates on worker threads with identical results; an evaluation running longer thanRULE_EVALUATION_TIMEOUT_MS(default 5000) is answered503and its worker replaced. Embedded:workers,evaluationTimeoutMs,operatorsModuleandterminateWorkers(). - TypeScript: manifest caching modes.
createManifestClienttakesmode(revalidate,ttl,permanent),ttlMs,staleIfError,refreshCron,storage(withlocalStorageAdapter) andonUpdate;gettakes an optionalchecksum; concurrent requests for one ruleset are shared;refresh()andclose(). The default behaviour is unchanged. - Refreshing holders.
RuleSetHolder(Java, Python) andHolder(Go) reload rules on an interval or a cron schedule, swap them atomically, keep the last good rules on failure and report each refresh to a listener. - Cron. One five-field cron syntax in TypeScript (
@rules-cascade/common/cron), Java (CronSchedule), Go (ParseCron) and Python (rule_cascade.cron), all tested againsttools/cron-cases.json. - Benchmarks.
make benchmeasures every runtime on the same bundle and requests (tools/bench-requests.json) and load-tests the rule server with and without workers.docs/performance.mdrecords measured numbers;docs/caching.mddescribes the caching modes.
Changed
- Specification. Canonical numbers are exact.
abskeeps 34 digits. Members of a protocol request are checked before a ruleset is looked up; optional members may benull. - TypeScript, Java. Both runtimes implement the evaluator and the compiler level and are at
version
1.0.0-alpha.2. - Rule server.
POST /evaluationschecks the body with the shape check every runtime applies and names the problem in its400answer. A ruleset that came from a bundle is listed with its id, version and checksum only.If-None-Matchis compared as RFC 9110 says: a list of entity tags, weak or strong, or*. A path with malformed percent-encoding is400, not500. A body over the limit is413without being read to the end. - Tools.
tools/lint_specs.pyalso checks that every pattern in the schema is portable, that the operator list inbindings/matches the schema, and that all generated files are current. - Makefile.
make verifyalso runs the Python package tests, the Go runtime, the release build, every engine over the protocol and the engine clients. - Documentation.
docs/architecture.md,docs/naming-conventions.md, ADRs 0001 to 0003,CONTRIBUTING.md,SECURITY.mdand the deployment notes describe the current design. The README has a table of supported versions (declared minimum, tested in CI, highest observed; no declared maximum) and says what is not verified: the Kubernetes manifests have never been applied, the WebAssembly module has not run in a browser, and thex-rule-cascadebinding is checked at lint time only. The claim that the runtimes agree beyond the suite now says which part can be repeated from the repository.
[1.0.0-alpha.1]
Added
- Specification 1.0 (draft): ruleset schema, normative semantics, evaluation API.
- Conformance suite: expression cases, load-error cases, fixture checksums and client manifests, golden tests, and a 300-case evaluation corpus.
- Reference implementation and linter in Python (
tools/rulecheck.py). - TypeScript runtime for browsers and Node.js, with a React hook and a manifest client.
- Java runtime with no dependencies.
- Rule server: stateless HTTP service with health probes, graceful shutdown and safe reload.
- Examples: organisation and feature rulesets, an OpenAPI binding, a React form, a Spring Boot API.
- Deployment: Dockerfile and Kubernetes manifests for the rule server.
- Bindings for OpenAI function tools and structured rule drafting.