Rule Cascade
Reference

Naming conventions

One convention per kind of name. The column "Enforced by" says what refuses a name that breaks the convention: schema is the ruleset schema (SCHEMAINVALID), load is a load-time check, and review is the reviewer.

One convention per kind of name. The column "Enforced by" says what refuses a name that breaks the convention: schema is the ruleset schema (SCHEMA_INVALID), load is a load-time check, and review is the reviewer. How to write the rules themselves is in the authoring guidelines; this page is only about names.

In a ruleset

ThingConventionExampleEnforced by
Ruleset idlower-case, dot-separated, broad to narrow: <org>.<domain>.<capability>acme.payments.transferschema
Ruleset versionSemantic Versioning1.4.0schema
Scope levelcamelCase noun; prefer enterprise, organization, businessUnit, agency, project, application, module, featurebusinessUnitschema (letters, digits, _); review
Scope idkebab-caseretail-bankingschema
EntityPascalCase singular noun, same as the OpenAPI schema nameTransferschema (letters, digits, _); review
TypePascalCase singular noun for the meaning, not the representationEmail, Money, CountryCodeschema; load (TYPE_UNKNOWN)
ParametercamelCase, unit in the name when it is not obviousmaxTransferAmount, reviewWindowDaysschema; load (PARAM_UNDECLARED)
FunctioncamelCase, named for what it returns; a predicate starts with is or hasisBlank, ageOnschema; load (FUNCTION_UNKNOWN)
Function parametercamelCase nountext, birthDateschema
Custom operatorx- and a kebab-case name for what it checks or computesx-luhnschema; load (OPERATOR_UNDECLARED)
Rule id<entity>.<field or aspect>.<constraint>, lower-case, kebab-case inside segmentstransfer.amount.positive, transfer.approve.four-eyesschema
Rule id, rule on a typetype.<type>.<constraint>type.email.format, type.money.two-decimalsreview
Rule id, inherited levelPrefix with the level that owns itorg.transfer.amount-limitreview
Rule kind extensionx-<name>x-auditschema
Page, screen, section, componentkebab-case logical id: what the user sees, not a framework class, selector or positiononboarding, profile, identity, name-inputschema (lower-case letters, digits, -); review
Field pointerJSON Pointer with the API's property names/beneficiary/swiftCodeschema; load (PATH_UNKNOWN)
Operationlower-case verb, kebab-case for phrasescreate, submit-for-reviewschema
Finding code<DOMAIN>-<GROUP>-<NNN>, upper-case, never reusedPAY-TRF-002, ONB-TYP-001schema; load (FINDING_CODE_DUPLICATE)
Message key<subject>.<reasonInCamelCase>; the subject is the entity, field or typetransfer.amountOverLimit, email.formatload (MESSAGE_MISSING)
Message placeholdercamelCase, ASCII letters and digits{limit}load (MESSAGE_ARG_MISSING)
LocaleLanguage tag, with a region where neededen, es, fr-CAschema
Command name<domain>.<past-tense-fact>risk.large-transfer-createdschema
Event type (ref)Reverse-DNS with a versioncom.acme.payments.transfer.large.v1review
Actor rolekebab-caserisk-officer, credit-managerreview
Taglower-case single wordcompliancereview
Golden test nameA sentence that states the behaviourblocked country is denied on the serverreview
Extension fieldx-<owner>-<name>x-acme-jiraschema (x- prefix)

Derived rulesets (rulecheck derive, see OpenAPI) name things mechanically: rule ids are <entity>.<property path>.<constraint>, finding codes GEN-<ENTITY>-<NNN>, message keys generated.<constraint>, and each rule carries x-generated-from.

Writing a good rule id

A rule id is permanent. It appears in findings, logs, overrides and audit records.

  • Name the constraint, not the implementation: transfer.amount.positive, not transfer.check1.
  • Do not encode severity or numbers that may change: amount-limit, not amount-max-25000-error.
  • When a rule is replaced, give the replacement a new id and retire the old one. Never reuse an id or a finding code for a different meaning.

Writing a good place id

A page, screen, section or component id is shared by the ruleset and the user interface: the interface sends it in view, and findings return it in location.

  • Name what the user sees: amount-panel, not MuiGrid-3 and not #amount.
  • Keep it stable across redesigns. Renaming one is a major change to the ruleset.
  • Use the same id on every platform that shows the same place: web, mobile, desktop.

Files

ThingConventionExample
Ruleset<domain>-<capability>.ruleset.yaml (or .yml, .json), kebab-case. Tools find rulesets by *.ruleset.*payments-transfer.ruleset.yaml
Bundle<ruleset id>.bundle.json. The rule server loads *.bundle.jsonacme.payments.transfer.bundle.json
Golden tests of a derived ruleset<name>.tests.yaml, next to the rulesetpayments-transfer.tests.yaml
OpenAPI description<domain>.openapi.yamlpayments.openapi.yaml
Specification files<name>.schema.json, <name>.openapi.yaml, under spec/v<major>/spec/v1/rule-cascade.schema.json
ADRdocs/adr/NNNN-<decision>.md0005-compile-once-bundles.md

In the repository

ThingConventionExample
Repository and directorieskebab-casepackages/typescript
Document keysruleCascade in a ruleset and a manifest, ruleCascadeBundle in a bundleruleCascade: 1.0.0
OpenAPI extensionx-rule-cascadeon the root and on each operation
npm package@<github-org>/rule-cascade[-<part>]@yarlisaisolutions/rule-cascade-server
npm commandsrule-cascade-<part>rule-cascade-node, rule-cascade-server
Maven coordinatesio.github.<github-org>:rule-cascade-<part>io.github.yarlisaisolutions:rule-cascade-core
Java packageio.github.<github-org>.rulecascade
Python distribution and packagerule-cascade, imported as rule_cascadefrom rule_cascade import load
Go moduleThe repository path of the packagegithub.com/YarlisAISolutions/rule-cascade/packages/go
Go packagerulecascade; the command lives in cmd/rule-cascaderulecascade.FromBundle
Commandrule-cascade; release files rule-cascade-<os>-<arch>, with .exe on Windowsrule-cascade-linux-arm64
WebAssembly modulerule-cascade.wasm
Engine name, as the version command of the engine protocol reports itrule-cascade-<language>rule-cascade-python, rule-cascade-typescript, rule-cascade-java, rule-cascade-go
Load error code, lint code, protocol error codeUPPER_SNAKE_CASE, identical in every runtimePARAM_LOOSENED, YAML_NOT_PORTABLE, BAD_REQUEST
Finding code of the engineUpper-case with hyphens, like every finding codeRULE-EVALUATION-ERROR
Conformance operatorsx-test-<name> for operators that exist only for the suitex-test-reverse, x-test-sum
Environment variableUPPER_SNAKE_CASERULES_DIR, RULE_SERVER_TOKEN, RULE_CASCADE_ENGINE
Branch<type>/<short-description>feat/date-operators
CommitConventional Commitsfeat(spec): add daysBetween
Tag and releasev<semver>v1.0.0

Versions

A ruleset has its own semantic version in metadata.version. Which change needs which bump is guideline 1.5 of the authoring guidelines. The specification (ruleCascade) and the bundle format (ruleCascadeBundle) are versioned separately; see specification section 10.

Rendered from docs/naming-conventions.md in the repository. Edit it there.

On this page