Skip to content
XBSL (1C:Element)
English
Esc
navigateopen⌘Jpreview
On this page

XBSL linter rules

The full list of linter checks, with severities and scope.

The full list of linter checks. This file is extended as rules are added; the live list at runtime is xbsl --list-rules (or the MCP list_rules). Currently there are 191 rules.

The table describes the toolkit as it ships. An installed plugin may add rules of its own and override severities and default states (see Extending), so the runtime list can differ from this one – xbsl --list-rules shows what your environment actually runs, and XBSL_NO_PLUGINS=1 shows the set below.

Boundary: the linter complements the compiler, it does not replace it

The linter works over text, the AST and the project model. Its rules know types at the first hop: the declared nominal type of a variable and its members, the project objects and the types they generate, enumeration values, the global types of the linked libraries (from the .xlib archive).

The engine DOES infer the type of an expression - xbsl.typeinfer answers for a receiver, a member, a constructor, a cast and a non-null operator, and the inference of chains and locals feeds hover and completion in the editor. The checks do not rest on it: the rules judge by the declared types - see below on what the linter does not do.

Some of the findings the compiler would catch as well: an unknown type, an argument count, a non-exception in catch, a return not matching the signature. The linter’s value there is not that it sees more, but that it sees them earlier - in seconds on your own machine, before the build and the deploy, pointing at the exact spot. The rest the compiler never checks at all: code-writing conventions, typography, project structure (duplicate Id, file pairing), unused variables, secrets in the sources.

What the linter does not do is anything that needs full inference of expression types: a redundant cast, a leaked resource in the general case, whether the TYPE of a returned value matches the signature. Two of those are worth separating. A structural return mismatch (a value in a void method, a bare return in a typed one) is caught by code/return-mismatch, while a return of a string from a method declared : Number slips through - telling that apart needs the expression’s type. And a resource is judged only in the one shape where the declaration itself says everything: code/unclosed-resource follows a closeable from its declaration to the loop over it in the same method; a resource that travels through calls or collections stays out of reach.

Code correctness is verified by the server-side compilation on deploy; the linter runs before it and removes common mistakes early.

How to read the table

  • Rule – the group/name identifier. The group (the part before /) lets you enable and disable rules in bulk.
  • Level error (a build and CI should fail), warning (a convention is broken), info (a hint, usually off).
  • Default – ✓ the rule is in the default set, – it is enabled explicitly.
  • Scopefile (the rule sees one file) or project (needs the whole-project index: duplicate Ids, unknown types, cross-module calls).
  • The link at the end of a description – the platform documentation section behind the rule. In VS Code the code of such a rule in the Problems panel opens that section right in the editor.

Tiers

Rules are split into tiers A-D by what they rely on. A tier is also a quick filter for --select/--ignore (alongside the group and the identifier): --select A,B runs only structure and text, --ignore D drops the semantics over stdlib.

Reading the columns: error · warning · info; ✓ – in the default set, – turned on explicitly; the scope is one file or the whole project.

Tier A - structure and YAML

The file exists, parses, the object has a unique UUID, the name matches the file.

Rule Scope What it checks
yaml/valid file YAML does not parse
yaml/duplicate-key file A scalar key set twice in one YAML mapping: the loader silently keeps the last value, every schema check reads the already-merged document, and the compiler rejects the file on deploy. The second and later occurrences are flagged, naming the line of the first; the << merge key and non-scalar keys are not judged, and keys compare the way the loader tells them apart (tag and text)
yaml/id-uuid file Id is not a UUID
yaml/id-required file The object has no Id
yaml/name-matches-file file Name does not match the file name
yaml/id-unique project Duplicate Id in the project
yaml/standard-field-length file A standard field longer than the platform limit (Name over 400 characters, Code over 50) - apply rejects the field and it drops out of the object docs
yaml/ref-needs-nullable file A reference type in a type position without ? (Goods.Reference, Edit<Goods.Reference>) - a reference has no default value, the compilation fails with Default value initialization is not supported docs
yaml/no-expression-in-literal file An =... expression inside a literal-typed node (Font: {Type: AbsoluteFont, Size: =...}) - the platform accepts only a literal there, compute the whole object instead docs
yaml/localization-key-unique file A key a LocalizedStrings dictionary declares twice - Strings and Templates share one namespace, and a translation file is judged too; the apply answers “Name is not unique” and rolls the project back docs
yaml/unused-component project An interface component placed nowhere and created nowhere: neither as a Type value in markup nor by new in code (code/unused-method cannot see it - the component’s methods are called by its own yaml). A use is a yaml value (a name as a dictionary KEY does not count) or any word of a module. Never judged: an entry point and VisibilityScope: Global - the public surface of a library. Without a project descriptor among the linted files the rule stays silent: on a subset a component placed outside would look dead
yaml/duplicate-subtree project A markup subtree repeating the shape of a subtree in ANOTHER file (names, ids and texts are left out of the shape): a new form is started by copying the neighbouring one. The 40-node threshold is measured - below it the rule catches layout, not copies. Never judged: a repeat inside one file, the data source of a list and a localized-strings dictionary; only maximal groups are named. Off by default: how much sameness is too much is a decision of the project
project/identifier file Project name or vendor is not an identifier docs
project/presentation file Project presentation is empty docs
project/version file Project version is not A.B.C docs
structure/xbsl-pair file Module .xbsl without a paired .yaml
project/path-matches-descriptor file The {{vendor}}/{{name}} path diverged from the descriptor – a build refuses the project before compiling docs
yaml/unknown-component-property file A markup key the component does not declare while ANOTHER component of the ui schema does (Checkbox + PlaceholderText, a property of Edit) - apply rejects the markup node as an unknown property; a name no component declares is left alone, the documentation does not list the yaml keys in full docs
yaml/inline-command-name file A Name on a command declared inline in the markup (an inline command-interface fragment or a single-command property) - the apply refuses the node (“a command name is allowed only in command-interface-fragment project elements”) and rolls back; reach the command through the handler parameter, or move the fragment into a project element of its own docs

Tier B - text and conventions

Encoding, newlines, whitespace, typography (dashes, quotes, ellipsis), line length, secrets in the sources.

Rule Scope What it checks
security/hardcoded-secret file A key or a password as a literal
typography/em-dash file Em dash in a comment
typography/ellipsis file Ellipsis character in a comment
typography/curly-quotes file Curly quotes
typography/guillemets-comment file Guillemets in a comment
typography/yo-in-text file Letter “ё” in interface text
whitespace/trailing file Trailing whitespace
whitespace/mixed-newline file Mixed newlines
encoding/utf8 file File is not UTF-8
style/tab-indent file Tab in the indentation docs
style/line-length file Line longer than 120 characters docs

Tier C - code structure, basic syntax and code-writing conventions

Block and bracket balance, loop and method headers, local variables and the style/ group - conventions from the documentation section “Code-writing recommendations”. Some style/ rules are off by default (accumulated debt, info): enable them with --select style to measure.

Rule Scope What it checks
code/parse-error file Syntax error (a full parse against the platform grammar) docs
code/statement-no-effect file Expression statement with no effect: the value is dropped (often a keyword typo, retun 5 for return 5)
code/return-mismatch file Return does not match the method signature (a value in a void method, a bare return in a typed one) - the compiler rejects such code docs
code/call-arity file Argument count of a local call outside the method’s [required, total] range docs
code/brackets file Unbalanced brackets () [] {}
code/blocks file Unbalanced blocks and ‘;’ docs
code/ternary-and-or file Compound ternary condition without parentheses docs
code/query-in-loop file A query inside a loop
code/param-type-required file Parameter without a type and without a default value docs
code/duplicate-annotation file Duplicate annotation on a declaration (an exact argument-free repeat of the name; annotations pile up until the nearest declaration, and a comment between them does not separate them) – the compiler rejects such a module docs
code/module-var-not-const file A var / val / use declaration at MODULE level - only a constant lives there, an expression outside a method body is refused by the compiler and the apply rolls the project back docs
code/param-redeclared file A val / var / use inside a method body with the name of the method’s own parameter, nested blocks (a loop, a branch, try) included – a method is one scope with its parameters in it, the compiler answers “a variable named X is already defined” at the apply and the project rolls back; loop and catch variables, lambda parameters and full-form lambda bodies are not judged docs
code/loop-header file Malformed ‘for’ loop header docs
code/invalid-string-escape file Invalid escape sequence in a string literal (\', regex-style \d) - the compiler rejects such a literal; valid are \н \в \т \\ \" \% \$ \ю<code> and the Latin spellings docs
code/unused-local file Unused local variable
code/unused-loop-var file Unused loop variable
code/ref-field-needs-req file Structure reference field without ‘req’ docs
style/boolean-compare file Comparing a boolean value with True/False docs
style/undefined-is file Checking Undefined with the ‘is’ operator docs
style/negated-is file Negating the ‘is’ operator on the outside docs
style/semicolon-line file ‘;’ not on its own line docs
style/wrap-operator file Operator at the end of a wrapped line docs
style/wrap-comma file Comma at the start of a wrapped line docs
style/camel-case file Name is not in UpperCamelCase docs
style/const-case file Constant is not in ALL_CAPS docs
style/exception-prefix file Exception name without the exception marker - a prefix on a Russian name, the Exception suffix on a Latin one docs
style/abbreviation-case file All-caps abbreviation in a name docs
style/enum-name-vid file Enumeration name starts with “Type” docs
style/collection-literal file Manual collection fill instead of a literal docs
style/redundant-tostring file An explicit ToString() call in a concatenation docs
style/interpolation file Concatenation instead of interpolation docs
style/type-colon-space file Spaces around the type colon docs
style/union-spaces file Spaces around ‘|’ in a union type docs
style/nullable-shorthand file Undefined in a type without the ‘?’ shorthand docs
style/redundant-type file Redundant type annotation on initialization docs
style/optional-params-last file Optional parameter before a required one docs
code/resource-bare-name file Resource{Resources/<file>.svg} - the key is a path RELATIVE to the Resources folder; spelling that folder out breaks the lookup docs
query/named-parameter file A named parameter &Name inside a query literal - the literal takes its values by interpolation (%Name) docs
code/this-in-static-method file The keyword this inside the body of a static method - a static method is common to the whole type and has no object context, the compiler rejects the project docs
code/instance-call-from-static file A bare call of an instance method of the same owner from a static method - the docs forbid it outright; call the method on a value or make it static docs
code/close-in-before-close file Close() inside BeforeClose – the platform ignores the call and nothing closes the form afterwards
query/no-isnull file ISNULL( inside a query literal – the query language has no such function
style/abstract-name file An abstract variable name (Data, Item, Object, String, Value, Document in either spelling - exact or with a digit tail like Data1) says nothing about the variable; a stem inside a longer name (ClientData) and structure fields (a serialization contract) are left alone docs
style/single-letter-name file A single-letter name of a variable, parameter or loop variable - per the names standard one-letter names belong only to short lambda parameters ((A, B) -> A + B) docs
style/negated-boolean-name file A boolean variable named from the negation (NotConnected, NoErrors) - the name comes from the affirmative (Connected, HasErrors); judged only where the boolean type is proven: a type annotation or a boolean literal initializer docs
style/type-in-name file A variable name starting with a container type name (the Russian spellings of array, structure and map) - the type is visible from the declaration and the editor, keep it out of the name docs
style/numeral-in-const-name file A spelled-out numeral in a constant name (TIMEOUT_ONE_MINUTE) describes the value - name the constant abstractly (TIMEOUT) so a value change does not break the name docs

Tier D - semantics over stdlib, forms and the metamodel

Needs the project index and platform data: unknown types and objects, enumeration values, the execution model (client/server), form handlers, properties and queries.

Rule Scope What it checks
yaml/choice-needs-static-list file ValueChoice without a static ChoiceList docs
yaml/slot-needs-list file A slot the ui schema types as Array<...> holding a single component instead of a list: the apply refuses such markup, and the lint used to keep silent docs
yaml/value-choice-title file A ValueChoice with an explicit SwitcherDisplayKind: Switcher sets a Title – the platform does not draw it and the field stays unlabeled; put the caption into a separate Label next to the switcher (nodes without an explicit kind and Array<...> ones – a checkbox group – are not judged)
code/unknown-type project Unknown type
code/catch-non-exception file The type in catch is not an exception (a stdlib non-exception or a local structure) - the compiler rejects such code docs
code/unknown-member file A member access on a variable of a known stdlib type - plain or a generic, whose arguments type the members and do not name them - that the type does not have (first hop, typos get a hint)
code/member-kind-mismatch project A stdlib method read as a property (or the other way round) docs
code/unknown-static-member project A member reached through a type name (DateTime.Minimal()) that the type does not have; the type of such a call carries on to the next hop. A bare name is read as a type only when the project gives it no other meaning; the module’s paired yaml counts even in a single-file check
yaml/foreign-not-public project A yaml reference (a type position, a FormType navigation target, the root of a binding chain =Module.Method() or a qualified Subsystem::Element name) to an element of another subsystem whose VisibilityScope is not InProject/Global - unreachable from outside its subsystem, and no import helps; the qualified form resolves by the subsystem it names docs
code/foreign-not-public project A module names an element of another subsystem whose VisibilityScope is not InProject/Global – in a written type position or as the root of a Module.Method() chain, the qualified Subsystem::Element form included: the compiler rejects the reference at that line, no import helps, and a @InProject annotation on the method does not either. The project module belongs to no subsystem, so every non-public element is foreign to it docs
code/call-arity-cross project Argument count of a <Module>.<Method>(...) call outside the target module’s signature range docs
code/undefined-name project Undefined name in an expression (a typo in a name) and in a short string interpolation ("?$format=json" substitutes the name format, \$ is needed) - the compiler rejects such code
code/unknown-object-type project Unknown project-object type
yaml/unknown-type project Unknown type in yaml
yaml/dynlist-missing-field project Missing dynamic-list field docs
yaml/dynlist-row-editing project An OnRowEdit handler on a list over a FLAT dynamic source: the event is declared for the node rows of a hierarchy, and on a flat list the platform never calls it - a click opens the object’s automatic form instead; give the object its own object form docs
yaml/dynlist-joined-table-param file A parameter (&Name) or a binding (=...) in the arguments or the filter of a JOINED table of a dynamic list: legal on the main table, never evaluated on a joined one – the compiler stays silent and the list fails at runtime; keep a literal in the yaml and assign the live value from code (Source.JoinedTables[i].Arguments) docs
yaml/dynlist-filter-disabled project A dynamic-list filter item is declared with Use: False while the paired module enables it by assignment: the first-render race – the platform draws the list without waiting for the code, and the first frame shows the whole table; declare the filter enabled with an empty value docs
yaml/list-form-needs-dynlist file The form inherits ListForm while its content holds a table over an ArrayDataSource and not a single type with DynamicList: the list-form skeleton is built around a dynamic-list table, and the navigation item silently disappears – give the table a dynamic list or inherit a plain form (Type: Form) docs
yaml/ref-input-auto-commands file A reference Edit with no Commands of its own: the platform draws its own button that opens the value in a separate window (for a reference input Auto unfolds into a command-interface fragment). The button is usually wanted, so the rule is informational and off; an empty fragment silences it docs
yaml/toggle-command-pair file Two adjacent UsualCommand nodes with mirrored Visible (=X against =not X) emulate one command with two states - the platform has the real thing: a SwitchableCommand carries the representations and images of both states, the initial Active is a literal, and the platform owns the state. A shared handler strengthens the case but is not required docs
yaml/dynlist-column-sort-lost file A column of a table over a dynamic list whose value CALLS something: the header will not sort, because the platform sorts by the FIELD of the source rather than by the text on screen. Bind the column to the field, or add a presentation field to the list itself. A column with DisableSorting: True is not judged – it has no sorting by declaration. Off by default: whether that column was meant to sort is not visible from the file docs
yaml/badge-column-image file A StandardTableColumn with Kind: Badge also sets Image – the platform does not show the picture: the value is drawn as tag pills and the picture is documented only for Kind: Picture; drop Kind (the picture stands next to the value text) or set Kind: Picture docs
code/unknown-enum-value project Unknown enumeration value docs
yaml/enum-needs-nullable project Enumeration without nullable; judged in both spellings - the input field is recognized as Edit<...>, the platform’s own English (InputField is no spelling of it and falls to yaml/unknown-type) docs
yaml/enum-default-value project The DefaultValue of an enumeration-typed field must be the bare name of a declared value: the type-prefixed spelling (LabelVisibility.Invisible) or an unknown name is rejected by the build docs
yaml/unknown-enum-value file A component property value outside the enumeration of the ui schema (ContentVerticalAlign: End - the vertical axis has Top, Center, Bottom, Baseline and no End)
yaml/bare-object-value file A bare word on a property that accepts Object - the platform expects a quoted literal, an = binding or a $ localized-string reference docs
code/unknown-resource project The name in Resource{...} is neither in the project’s Resources folders nor in the platform’s image library docs
form/unknown-handler project Form handler not found in the module docs
form/handler-signature project Handler signature does not match the event docs
code/unknown-form-component file Access to a component the form markup does not declare docs
code/server-call-from-handler project Server method is unavailable to a client handler docs
code/image-binding-server-call project The Image property of a platform component is bound to an expression whose call – directly or transitively through client methods – resolves into a server method (an element module of a server kind, a common module with Environment: Server, a @OnServer method): the image arrives by its own server round-trip after the rows are drawn and is requested again on every redraw; hand it over with the data (a field of the query or of a joined table) or build it from client-side data docs
code/client-annotation-in-server-module project Client annotation in a server common module docs
code/client-module-in-http-service project Client common module in a server environment docs
code/server-annotation-in-client-module project Server annotation in a client common module docs
code/query-needs-server project A Query{...} block in a method of a client-side module (a form, or a common module whose Environment involves the client) that carries no @OnServer - the type does not exist on the client and the compiler rejects the build docs
code/local-method-cross-component project Cross-component call of a local method docs
code/local-method-cross-module project Cross-module call of a local method docs
naming/yo file The letter yo in a name docs
naming/underscore file Underscore in a name docs
naming/abbreviation file All-caps abbreviation in a name docs
naming/latin-term file English term spelled in Cyrillic docs
naming/enum-vid file Enumeration name with the word “Type” docs
naming/kind-in-name file Element kind inside its name docs
naming/filler-word file Filler word in a name docs
naming/module-suffix file Environment suffix in a common module name docs
naming/number file Wrong number for the element kind docs
naming/boolean-name file Boolean attribute name docs
naming/presentation file Element presentation docs
naming/prefix-by-kind file Kind-specific name without its prefix docs
code/unknown-ns-object project Unknown object in a kind namespace
query/unknown-table project Unknown table in a query docs
query/in-subquery-composite project ‘IN’ with a subquery over a composite type docs
yaml/unknown-property file Unknown object property
code/reserved-name file Reserved name: the type keyword in either language (type, Type and the Russian spelling) as a structure field or a parameter - the server apply refuses all three (the capitalized one confirmed by a live apply)
yaml/builtin-property-name file Built-in property name clash
yaml/size-needs-no-stretch file A size without disabling the stretch docs
yaml/col-width-needs-no-stretch file A numeric Width on a table column (all three column kinds) without HorizontalStretch: when the column stretches the number acts as a share of the free space rather than pixels – the column comes out wider than asked and the content drifts away from its neighbour. A pixel width needs HorizontalStretch: False, a share with a guaranteed minimum – MinWidth. Off by default: width-as-a-share is a legitimate technique, statically indistinguishable from the trap docs
yaml/matrix-group-max-width file A numeric MaxWidth on a group that lays out as a matrix: the maximum is also the AVAILABLE width, so the automatic columns are laid out by it rather than by the window and a phone draws the page at desktop width (the content runs off the right edge). Answer Auto instead. Off by default: a desktop-only page lives with a maximum fine docs
yaml/card-literal-stretch-weight file A literal StretchWeight on a card or on a group inside one: the weight is a flex with a ZERO basis, and in a vertical column (the mobile layout) that basis applies to the HEIGHT - Safari collapses the card and clips it with the rounding, Chrome shows nothing. Drop the weight on a phone through a binding. Off by default: a card living only in a wide row keeps it legitimately docs
code/unused-method project Method is never referenced
code/duplicate-method-body project A method body repeated word for word in ANOTHER file: the normalized body (comments, blank lines and indentation dropped) of at least five lines is compared. A platform hook is told apart by its @Handler annotation rather than by a list of names - the same hook body in every object is normal; copies inside one file are not judged. Off by default: whether two copies should become one method is a design decision
yaml/missing-import project A yaml reference (a type position, a FormType navigation target or the root of a binding chain =ForeignModule.Method()) to a public element of another subsystem that the Import section does not list – an import in the paired module does not cover the markup; a binding root is judged after subtracting everything that explains the name on its own: the declarations of this yaml, of the paired module and the implicit platform names docs
code/unused-import project A module imports a subsystem whose elements its CODE never mentions - the platform editor reports such imports, and they accumulate as the code that needed them is rewritten. A reference from the PAIRED yaml is not a use: the yaml has an import section of its own docs
code/missing-import project A module names the type of a public element of another subsystem without an import line for it - the project fails to compile at that line. Both WRITTEN type positions (a parameter, a variable, a return, new, as, is, generic arguments) and the root of a chain (Module.Method()) are judged; for a root everything that explains the name on its own is subtracted first: the declarations of the method and the module, the implicit names of the platform and the sections of the PAIRED yaml docs
yaml/missing-subsystem-usage project Elements and modules of a subsystem import another subsystem while the description of their own (Подсистема.yaml) does not list it under Using - the project fails to apply, and that is learnt at deploy time. An import gives the short names, but it is Using that permits the subsystem; the diagnostic sits on the subsystem description, where the fix goes docs
yaml/computed-binding-assigned project Every instance of a component binds a property with a COMPUTED expression while the component assigns that property in its own module - the platform crashes on the assignment (IllegalStateException). A named argument is not an assignment, and a code-built instance, a bare-path binding, a literal or an unbound instance make the assignment legal - the rule fires only when every instance is bound computed
yaml/localization-missing-import project An unqualified $Dictionary.Key whose dictionary lives in a subsystem this yaml does not import - the apply refuses the node as a not-imported namespace; an import in the paired module does not cover the markup, and the qualified $Subsystem::Dictionary.Key form needs no import docs
yaml/presentation-field file The presentation field of an object docs
yaml/unexpected-type-argument file A type argument on a property the ui schema declares without one - another type, rejected when the build is applied (a form’s AdditionalCommands takes CommandInterfaceFragment, not CommandInterfaceFragment<UsualCommand>); an English tree is judged the same - the key, the component, the property and the type head are canonized, and the argument is compared with the default name by name in either spelling docs
yaml/property-since-compat project A component property newer than the project’s CompatibilityMode (the ui schema records the version it appeared in) - apply rejects it as an unknown property docs
query/deletion-mark-immediate project A deletion-mark condition in a query on an object whose DeletionMode is Immediately - such an object has no mark and the query fails on apply docs
code/load-object-unwrap file A force-unwrapped LoadObject() result on a reference from a field of another record or of a tabular-section row (Row.Service!.LoadObject()!) – the record may be deleted physically (DeletionMode: Immediately, the deleted-items form), and the unwrap fails the whole pass; check the result for Undefined (the query row’s own .Reference is not judged) docs
yaml/item-id-required file A metadata collection item (an attribute, a tabular section, an enumeration item, an access-key parameter) without the Id its class declares - apply answers ID required
code/unknown-row-field project A field addressed on a dynamic list row (DynamicListRow<Form.Type>) that the list’s Fields do not declare docs
code/row-field-null project A dynamic list field taken through a reference (Owner.Number) is `
yaml/unknown-attribute-property file A key an attribute’s own metamodel class does not declare (Length on a regular attribute - the built-in Code declares it, a Number attribute has IntegerPartLength) - apply rejects the object
yaml/empty-group-sized file An empty Group with Height/Width (a literal – always; an =... binding – only without a Name) – the renderer drops the node and there is no gap
yaml/insert-row-needs-align file A horizontal group holding an HtmlContainer insert and no VerticalContentAlignment: children are laid out on the BASELINE, and the insert carries one of its own, so the element holding it slides down against its neighbours (50 px on a live row). The nearest horizontal ancestor answers, so a row whose inner strip is already aligned stays silent docs
yaml/hint-too-long file A Tooltip longer than the render limit – the tail is not shown at all
yaml/popup-in-markup project A PopupComponent (or a project component transitively inheriting it) placed in the yaml markup: the content is drawn right in the form flow before the window ever opens – the platform has no property restricting the drawing to the window, and hiding it via Visible breaks the window itself; build the window in code on every opening – a new PopupComponent(...) followed by OpenInPopupWindow() docs
yaml/date-input-needs-plain-date file Edit<Date?> – the renderer silently drops a date input that allows the empty value; make the type plain and express “not set” with the empty date docs
yaml/binding-needs-auto project A binding of a plain component property calls a method declared nullable - the client registers an “unexpected Undefined value” error on every recomputation; “not set” is the Auto value
code/client-available-needs-context project @AvailableFromClient on a method of an interface component module that is neither static nor @Contextual – the component type is not a singleton, so the apply rejects the modifier docs
code/client-available-unused project A method declared @AvailableFromClient with no client place in the project naming it - neither a module of the client environment, nor a client method of a server module, nor a yaml, nor a string literal. The annotation opens a surface to the client that nobody uses. Off by default, like code/unused-method: a client call is not always visible statically docs
code/server-module-in-client-context project A Module.Member(...) access to a common module with Environment: Server from a method that runs on the client (an interface component, a command, a client common module) – the type does not exist on the client docs
code/component-in-server-context project A Component.Member(...) access to an interface component from code compiled for the server – a @OnServer method anywhere, or an unannotated method of a server or client-and-server module: the component’s type lives on the client, and the server compilation refuses with “Variable X is not defined” docs
yaml/delete-current-needs-immediate file OnReferencedObjectDeletion: DeleteCurrent on an attribute whose owner has a DeletionMode that only marks (DeletionMark is also the default) – the apply answers Action DeleteCurrent cannot apply to object with a DeletionMark docs
code/access-context-read-noop project Extending the access context with the read privilege for a type whose yaml says Read: PermitEveryone: everyone may read it already, so there is nothing to grant - the call only suggests the data is guarded. With that privilege alone the whole line goes; among others, only it does docs
code/per-object-permissions-need-common project An object calculates its permissions per object, but its module declares no ComputeAccessPermissions handler – the common calculation is required even then, if only to return an empty array docs
code/permission-field-not-declared project Inside ComputeAccessPermissionsForObjects a field outside ComputePermissionsBy is read, or a declared field is reached through Entity instead of the record docs
code/permission-handlers-need-recalc project A module declares a permission handler (ComputeAccessPermissions and kin) while the project calls RecomputeAccessPermissions for that entity nowhere - the platform never calls the handler by itself, so a permission edit silently does not act; a recompute with a non-entity receiver (the documented loop form) stands the rule down, kinds with no recompute method (rights elements) are not judged docs
code/permission-right-not-computable project Handler ComputeAccessPermissions (or ...ForObjects) grants a permission the entity’s yaml does not declare computable (PermissionsComputed / PermissionsComputedForEachObject, explicitly or through Default) – the build applies, and the permission recomputation fails at runtime: the permission is not marked as computed. Permissions are collected only from new AccessPermission(...) constructors in both namespaces (Entity.Privilege.*, HttpServicePrivilege.*), transitively over project calls – delegation into a shared rights module is followed and the finding is bound to the entity; AccessContext.Append does not count, under-granting is legal, kinds without access control are not judged docs
yaml/placeholder-key-in-strings file A key carrying the placeholder $0 in the Strings section of a LocalizedStrings dictionary: the section compiles to a method WITHOUT parameters, so a call with an argument fails the apply with an “unknown method” answer docs
yaml/localization-ref-to-template project A $Dictionary.Key reference pointing at a key of the Templates section: a reference resolves against Strings alone, and the apply fails with “localized string not found” (the stand rolls back). A template key nobody references is left alone - code calls it legitimately docs
code/compare-with-localized project A localized value (Dictionary.Key(), Presentation()) compared against a literal or against a second localized value – in another language the branch simply never runs docs
code/url-params-partial-encoding file A call of the Url method WithRequestParameters: it encodes a parameter value only partially – “&” and “=” inside the value stay separators, and a value that is itself an address arrives cut at its first “&”; build the string with the parameters object and glue it to the base address. Off by default: whether a value can carry “&” is not statically visible docs
code/bound-property-assign file A property COMPUTED by an expression in the paired markup (Height: =Common.IsNarrowScreen()?820:528) is assigned from code - the platform refuses such an assignment, and inside a try/catch the refusal is invisible; a data binding (a bare path) is left alone, it is two-way by design
yaml/event-needs-importance file An EventLogEvent description that does not set Importance: its default is FromConstructor, so the platform then demands the value in EVERY constructor, and one write that omits it fails the apply on the constructor line; an explicit Importance: FromConstructor states the choice and silences the rule docs
yaml/event-property-type file An EventLogEvent property type outside the platform’s closed list: a project enumeration cannot go there – the refusal comes only from the server-side compilation and costs the deploy; the list is read from the metamodel (EventLogEventProperty.Type), ? and a Std:: qualification are tolerated, variant values are written as string codes with the allowed codes listed in the property’s Description docs
code/collection-field-needs-req file A structure field whose generic type has no argument-less constructor (ReadableArray<String>) and no req, ? or initializer - the apply answers “cannot be initialized with a default value”; Array<String> and the like are constructible empty and are left alone docs
code/var-needs-init project A variable declared by type alone where the type has no constructor and no default value (var Response: HttpResponse) - the compilation answers “has neither a constructor nor a default value”; an enumeration, an annotation, a singleton and a name shadowed by a project type are skipped docs
code/unknown-tabular-member project A member access on a tabular section’s row collection that the array type does not have (Object.Section.Member in an object form module, the bare section name or this.Section in the entity’s modules) - the collection is Array<Entity.Section>, and the other platform’s habitual Count() is called Size() here; a module named after the section shadows it, attributes are not judged
code/global-unavailable project A call of a global name outside its environment: Message (client-only) in a server module - the apply answers “the method is unavailable in the current environment”, the dynamic evaluation globals (server-only) in a client method without @OnServer; @OnClient/@OnServer override the module’s environment, the availability comes from the per-member availability lines of the global context packages docs
style/shadow-project-name project A variable, parameter or method named like a project element (a Warehouses variable next to the Warehouses catalog) - the declaration shadows the element for that scope; platform handler parameter names never collide with project names docs
style/shadow-own-property project A local VARIABLE named like a property of the element the module belongs to: inside the method the name resolves to the variable, so an assignment never reaches the property. Judged only where such a property is in scope - the module of an interface component and the object module; a parameter of that name is the ordinary way to pass a value in and is left alone docs
code/unclosed-resource file A closeable resource (val Selection = Query{...}.Execute()) abandoned by an early exit from the loop over it: the platform closes a full pass by itself, while a return or a break in the middle leaves the resource open and the platform logs an unclosed-resource event; declaring the variable with use closes it on every exit path. A resource that arrived as a parameter, one the method closes by hand and one it returns to its caller are left to the author docs
code/use-needs-closeable file The use modifier over a type the catalog describes and that does not inherit Closeable - the modifier exists for the automatic Close(), and the compiler refuses the declaration docs
conventions/untranslated-visible-literal project Visible text left as a Cyrillic literal where the project already references the same property into a localization dictionary - the intent is counted per element kind, so a same-named property of another kind is not judged; silent on a project whose descriptor lists fewer than two localization languages
conventions/untranslated-code-literal project Visible text left as a Cyrillic literal in a MODULE - judged by the SINK it reaches (an argument of the platform message call, a property of an event-log event, or either of them one step away through a method that forwards its parameter); markup, pure interpolation and single words are skipped, and the rule is silent on a project whose descriptor lists fewer than two localization languages
conventions/missing-translation project A project token or a Cyrillic comment line the project’s translation dictionary does not cover yet - one finding at its first occurrence in the file; silent unless an xbsl-translation dictionary lives next to (or above) the project (see xbsl translate)
code/unknown-structure-field project A field access on a structure declared IN THE PROJECT is checked against its declaration: rename a field and its reader in another module turns red here rather than on the server apply. The type comes from the variable’s declaration (Module.Structure, a bare name for the declaring module), from a new constructor and from the element type of a for X in List loop; a name declared with anything else in the method, a namesake of a stdlib type, the second hop of a chain and Latin member spellings are not judged

Group details

Queries: IN with a subquery over a composite type (rule query/in-subquery-composite)

A platform standard: IN with a subquery over an expression of a composite type is implemented inefficiently on most DBMSs, so the condition is written with EXISTS instead. The rule is a warning – the standard is mandatory:

WHERE T.Value IN (SELECT F.Value FROM Filters AS F)                    // warning
WHERE EXISTS (SELECT 1 FROM Filters AS F WHERE F.Value = T.Value)      // this way

A type counts as composite when the yaml spells two or more alternatives (String|Number|?): the ? is not a type but the admissibility of Undefined, and Array<String|Number> is not composite either. Only a field whose type is known for sure is questioned: Alias.Field or Table.Field, where the alias is unambiguous within the block and the field is found in the table’s yaml; a list of values (IN (1, 2, &Codes)) is not what the standard is about. Both spellings of the query language are understood - the English IN, NOT, SELECT and their Russian equivalents.

Project properties (the project/ rules)

Four rules from the standard “Filling in the project properties”: Vendor and Name are identifiers built from the presentations, every word capitalized; Presentation and VendorPresentation are filled in - the official name of the project and of the company that developed it; Version is three numbers A.B.C (semantic versioning), not 1.0.

Names of project elements (the naming/ rules)

Twelve rules from the platform standard “Names of project elements” – it is mandatory in new code, so all of them are warnings. They read the descriptions (.yaml): the name of the element itself and the names in its Attributes, Dimensions, Resources, TabularParts and enumeration values.

The number of a name is checked against the kind: catalogs, documents, registers and tabular sections are named in the plural, enumerations and structures in the singular (naming/number). For a Russian name this is morphology, not a guess by the ending: a singular noun that the standard allows is told apart from a plural that reads as a genitive singular without the case. Needs the [morph] extra (pip install "xbsl[morph]"); without it Russian names stay silent. An English name (a translated tree) is judged by its last word with suffix heuristics and the irregular plurals listed, and needs no extra; mass nouns and ambiguous tails are left undecided.

The rest: the letter yo and underscores in names, an abbreviation written in mixed case instead of all caps, an English term transliterated rather than kept as the original (Xml, not its Cyrillic spelling), an enumeration named with the word for type where the standard asks for the word for kind, the element kind repeated inside its own name, filler words such as the ones for management or manager, an environment suffix on a common module name (the environment is a property, not a name), a boolean attribute named by a negation instead of the positive form, an empty Presentation, and the prefixes required for certain kinds - access key, right and navigation.

Code style conventions (the style/ rules)

Twenty-eight rules that follow the platform documentation (“Code style conventions”, “Language idioms”) and the “Variable and constant names” development standard: layout and expression wrapping, naming, type descriptions and signatures, collection literals, string interpolation, and checks of boolean values and Undefined.

Of the variable-names standard the token-provable part is checked: abstract names, single-letter names outside lambdas, Cyrillic and Latin abbreviations not written as one word, boolean names built from the negation, a container type inside a name, numerals inside constant names, and the shadowing of project element names. Left to the author and review: redundant words in a name, abbreviations beyond the capitalization law, digits in place of a qualifier over a meaningful stem (Stage1 and Data1 differ only in meaning), and the abstractness of a constant name beyond numerals (the role of INITIAL_STAGE against the value of STAGE_QUESTIONNAIRE is invisible to tokens).

Rules that clean code already satisfies are enabled by default (warning) – they guard against regressions. Rules that typically fire on accumulated legacy debt are info and disabled; enable them to measure the debt and pay it down:

xbsl path/to/sources --select style     # ONLY these rules (replaces the default set)
xbsl path/to/sources --enable style     # the default set PLUS these
xbsl path/to/sources --ignore style     # the default set minus these

--select, --enable and --ignore accept a rule id, a group (the part before /) or a tier letter, repeated or comma-separated. --select narrows to exactly the given rules; --enable switches on off-by-default rules on top of the defaults.

Query{ ... } blocks (the query DSL) and string literals (HTML/CSS/SVG in web views) are excluded from these checks. Not covered, and left to the author and review: indentation being a multiple of four, collection idioms, Rows.Join() for bulk concatenation, the ?. / ?? idioms, and case instead of an else if chain.

Code semantics (the code/ rules)

The largest group - sixty-four rules, thirty-four of them errors. This is what the compiler rejects or what the platform does differently from how the code reads: an unknown name or member, the arity of a call, the environment (client code in a server method and the other way round), an instance reached through its type, a caught non-exception, an unclosed resource, a walk over a collection while it is being changed, and the platform traps whose only sign is the shape of the code. Some of the rules are project-scoped (--stdin does not run those): they need the paired yaml and the names of the objects.

Element descriptions (the yaml/ rules)

Fifty-seven rules over the descriptions (.yaml): required and unique ids, known keys and types, references to components, handlers and localized strings, what the platform requires of field types (a reference and an enumeration admit an empty value), the settings of dynamic lists and forms, and the layout traps that apply without an error yet draw differently from the intent. Six rules are info and off: they say “this is how the platform works”, not “this is a mistake”.

Project conventions (the conventions/ rules)

Rules about what the PROJECT agreed on rather than what the platform demands. The base set carries the bilingual-project family: conventions/untranslated-visible-literal (on by default) reports visible text left as a Cyrillic literal where the project already routes the same property through the localization dictionary, and conventions/untranslated-code-literal with conventions/missing-translation (both off) extend that to module literals and to the translation dictionary - whether every human-readable string must come from the dictionary is a per-project decision, so the base set does not impose it.

The group is also the extension point by design: a project plugin registers its own house rules under conventions/ (a ban on task numbers in comments, internal references and the like) and decides their severity and defaults for that project - see Extending. Runtime truth is xbsl --list-rules; the table above lists the base set only.

The small groups

  • typography/ - typographic characters in prose and comments: em dash, the ellipsis character, curly quotes, guillemets in comments, plus the letter “ё” in the text a user reads;
  • whitespace/ - trailing spaces and mixed newlines;
  • encoding/ - a file that is not UTF-8;
  • structure/ - the pairing of Name.yaml and Name.xbsl;
  • security/ - a secret in the sources (a token, a password, a key);
  • form/ - a form handler the module does not have, and a handler whose signature contradicts the event of the component (project-scoped rules);
  • query/ - queries: an unknown table, ISNULL, a named parameter, an immediate deletion mark and the standard about IN with a subquery (discussed above).

Enabling and disabling

--select and --ignore accept a rule identifier, a group (the part before /, e.g. style) or a tier letter A/B/C/D. A plugin may override a rule’s severity (the xbsl.severity entry-points group); XBSL_NO_PLUGINS=1 disables plugins and restores the built-in values from this table.

Last updated on September 6, 2026

Was this page helpful?