Skip to content

Conformance levels

An implementation’s conformance claim is a level, not a vibe. The levels are cumulative: claiming L(n) means L(0..n−1) hold too, and the shared corpus gates every level — fixtures are never edited to make an implementation pass.

L0 — Notation. The text syntax parses and canonicalizes: every documented construct round-trips (parse(to_text(m)) == m for every model the implementation can represent), rejection is clean (ParseError, never a crash), and the parser accepts exactly the grammar the PARG contract describes.

L1 — Semantics. The parse is a semantic model, not typography: isotopes bind atoms, charges and oxidations are typed, bond kinds and directions are model data, reactions carry conditions. The wire form (asciichem-model v1) round-trips: model → wire → model is equal.

The perception pass is part of L1: chemistry the syntax leaves implicit is derived once, as model services, and every implementation must derive the same values. Today that covers implicit hydrogens (aromatic bonds order 1.5 for H-counting, so c1ccccc1 and C1=CC=CC=C1 perceive one hydrogen per carbon; a non-integral or over-valent sum yields no answer rather than an invented one) and aromatic rings (six-membered, fused-system sp2 rule; five-membered rings are a documented limitation). The shared corpus pins both — including the declines.

L2 — Render. Every model node renders to MathML (byte-golden against the corpus), canonical text, and the wire form. Rendering is deterministic across runs — visual and textual regression goldens exist for every construct.

L3 — Stereo. Tetrahedral parity (@/@@ → TH1/TH2), directional bonds (/, \ → up/down), wedge/hash depiction semantics. Stereo survives every round-trip (text, SMILES, wire, CML), enantiomers and diastereomers stay distinct through the canonical form, and canonical SMILES emits parity-correct tokens.

L4 — Identity. The model resolves to authoritative identity: InChI/InChIKey via the opt-in engine, identifier cross-validation (@inchi/@smiles/@cas checked against the structure), and citation-grade resolution (one bibitem per (substance, source) the author chose).

LevelRuby (reference)TypeScriptPythonRust
L0 notationyesyesyesyes (canonical text) + parse contract — consumes the PARG artifact
L1 semanticsyesyesyesyes (round-trip subset — model subset mirrors the reference TransformRules; out-of-subset constructs report unsupported)
L2 renderyes (MathML goldens, canonical text, wire)yes (text, structural SVG, MathML goldens, wire)yes (text, wire, MathML goldens, SVG byte-exact with TS)yes (MathML goldens, canonical text, wire, SVG)
L3 stereoyes — text, SMILES, wire, parity-correct tokens, ring closuresyes — chirality, directional bonds, parity-correct canonical SMILESyes — chirality, directional bondsno
L4 identityyes — resolver + InChI engine (now native-capable: the NativeEngine drives the Rust engine’s C ABI; the binary engine remains the fallback) + OPSIN adapter + identifier cross-check shipped; sources settled: PubChem default, Common Chemistry opt-in (CC BY-NC, attributed)partial (InChI via engine)noyes — the native engine (inchi-rs): full identifier, /t /m /s /b stereo layers, and the InChIKey natively computed, gated 1559/1559 against the recorded oracle corpus; reachable from Ruby through the NativeEngine and from Python/JS through its C ABI and bindings

The matrix is regenerated from the conformance suite; a level claim without the green corpus run behind it does not ship.

Play