List the validation rules¶
Available in: Python · Node · CLI · Browser
Enumerate the validator's numbered rules — the same catalogue every surface runs — to drive a UI legend, a docs page, or a coverage check without hard-coding rule numbers.
# what this shows: enumerate the validator's numbered rules + report the dictionary edition a file resolves to.
import laterite
# list_rules() returns one rich dict per numbered rule (keys incl. rule/title/severity/fixable/...).
rules = laterite.list_rules()
# dict_for(path) resolves a file to its (version, reason) tuple — e.g. ('4.1.1', 'exact').
ver = laterite.dict_for("examples/sample_site.ags")
print(len(rules))
print(sorted(rules[0])[:6])
print(ver)
assert len(rules) >= 20 and isinstance(rules[0], dict)
assert isinstance(ver, tuple) and ver[0] == "4.1.1"
laterite.list_rules() returns one rich dict per numbered AGS4 rule — 27 of
them, covering 1, 2, 2a, 2b, 3 … through 20. Each dict carries the
rule number (rule), a human title, a prose checks description, a
severity (error, or mixed where the rule flags some findings for
information only), a fixable flag (whether .fix() / lat fix can
repair it mechanically), and the observations it relates to in the
divergence catalogue. It's the
programmatic mirror of the rule table the CLI prints — drive a docs page, a UI
legend, or a coverage check off it without hard-coding rule numbers.
laterite.dict_for(path) resolves a file to the dictionary edition the
validator will judge it against, as a (version, reason) tuple — here
('4.1.1', 'exact') because the file's TRAN_AGS declares 4.1.1 and that
edition is bundled. The reason tells you how the pick was made (an exact
match, a fallback, …); see Dictionary selection
for the resolution order.
Filter the list the same way you'd filter any list of dicts — e.g. just the mechanically-fixable rules:
The severity field is mixed for rules that emit both errors and
information-only findings (Rule 1 character-set, Rule 16 ABBR pick-lists, Rule
18 dictionary references); everything else is a hard error.
// what this shows: listRules() enumerates the numbered AGS4 rules; each RuleMeta carries severity + fixable.
import { listRules } from "laterite";
import assert from "node:assert/strict";
const rules = listRules();
console.log(rules.length);
console.log(Object.keys(rules[0]).sort());
// The mechanically-fixable rules, straight off the metadata — no hard-coded numbers.
const fixable = rules.filter((r) => r.fixable).map((r) => r.rule);
console.log("fixable:", fixable.join(", "));
assert.ok(rules.length >= 20);
assert.deepEqual(Object.keys(rules[0]).sort(), [
"checks",
"fixable",
"observations",
"rule",
"severity",
"title",
]);
assert.ok(fixable.includes("1")); // Rule 1 (character set) is mechanically fixable
27
[ 'checks', 'fixable', 'observations', 'rule', 'severity', 'title' ]
fixable: 1, 2a, 4, 6, 7, 8, 11a, 11b
listRules() returns the same 27-entry catalogue as an array of RuleMeta
objects — rule / title / checks / severity / fixable / observations,
the one-for-one mirror of Python's dicts. It's synchronous and needs no DuckDB
peer, so a Node service can render a rule legend or a fixable-only filter
(rules.filter(r => r.fixable)) straight off the metadata.
lat rules prints the whole catalogue as a table — no file
needed:
┌──────┬──────────────────────────────────────────────────┬──────────┬──────┐
│ Rule ┆ Title ┆ Severity ┆ Fix? │
╞══════╪══════════════════════════════════════════════════╪══════════╪══════╡
│ 1 ┆ Character Set ┆ mixed ┆ yes │
├╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┤
│ 2 ┆ Data Groups and Data Rows ┆ error ┆ │
├╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┤
│ 2a ┆ Line Termination ┆ error ┆ yes │
├╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┤
│ 2b ┆ Group Header Structure ┆ error ┆ │
├╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┤
│ 3 ┆ Data Descriptors ┆ error ┆ │
├╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┤
│ 4 ┆ Field Count and GROUP Row Format ┆ error ┆ yes │
├╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┤
│ 5 ┆ Quoted Fields ┆ error ┆ │
├╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┤
│ 6 ┆ Embedded Carriage Returns ┆ error ┆ yes │
├╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┤
│ 7 ┆ Heading Order and Duplicates ┆ error ┆ yes │
├╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┤
│ 8 ┆ Typed Values ┆ error ┆ yes │
├╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┤
│ 9 ┆ Dictionary Headings ┆ error ┆ │
├╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┤
│ 10a ┆ KEY Field Uniqueness ┆ error ┆ │
├╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┤
│ 10b ┆ REQUIRED Field Non-Emptiness ┆ error ┆ │
├╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┤
│ 10c ┆ Parent-Child Linkage ┆ error ┆ │
├╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┤
│ 11a ┆ Record-Link Delimiter ┆ error ┆ yes │
├╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┤
│ 11b ┆ Record-Link Concatenator ┆ error ┆ yes │
├╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┤
│ 11c ┆ Record-Link Resolution ┆ error ┆ │
├╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┤
│ 13 ┆ PROJ Group Presence and Row Count ┆ error ┆ │
├╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┤
│ 14 ┆ TRAN Group Presence and Row Count ┆ error ┆ │
├╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┤
│ 15 ┆ Unit Definitions ┆ error ┆ │
├╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┤
│ 16 ┆ Abbreviation Definitions ┆ mixed ┆ │
├╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┤
│ 17 ┆ Data Type Definitions ┆ error ┆ │
├╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┤
│ 18 ┆ DICT Group for Non-Standard Names ┆ mixed ┆ │
├╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┤
│ 19 ┆ GROUP Name Format ┆ error ┆ │
├╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┤
│ 19a ┆ HEADING Name Length and Character Set ┆ error ┆ │
├╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┤
│ 19b ┆ HEADING Name Structure and Cross-Group Borrowing ┆ error ┆ │
├╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┤
│ 20 ┆ File Attachments ┆ error ┆ │
└──────┴──────────────────────────────────────────────────┴──────────┴──────┘
The Severity and Fix? columns are exactly the severity / fixable
fields the library surfaces expose — mixed marks a rule that also emits
information-only findings, and yes marks one fix can repair mechanically.
Open the web app and find the rule catalogue under Tools — the same 27 numbered rules with their titles, severities, and fixable flags, rendered from the wasm build. When a validation run flags a finding, it links back to this explainer so you can read what the rule checks without leaving the page.
Every surface reads the same rule catalogue from the one engine, so the numbers, titles, severities, and fixable flags never drift between a Python legend, a Node UI, the CLI table, and the browser explainer.
See also: CLI reference · Dictionary selection