A structure sanity card that checks geometry, symmetry sensitivity, and bond lengths before trusting any downstream computation. Demo: a Co3O4 CIF that reads as Fd-3m but has oxygen atoms 0.32 Å apart.
I have a CIF of CoO spinel that passes every symmetry check. Sglib reports Fd-3m (#227) robustly across tolerance thresholds from 0.01 to 0.30 Å. The lattice is cubic, 8.084 Å, 56 atoms, all sites ordered. By the standards most computational pipelines use, this structure is clean.
It also has two oxygen atoms 0.32 Å apart.
That is not a bond. That is not even a close contact. Two oxygens at 0.32 Å are sitting on top of each other. There are 96 such pairs in this cell, all at exactly 0.3201 Å, with zero dispersion. The structure is systematically corrupted, and symmetry analysis cannot see it.
The CIF declares P1 and lists all 56 fractional coordinates explicitly. The oxygen positions are drawn from the correct set of fractional values for an Fd-3m spinel with u ≈ 0.389: {0.111, 0.139, 0.361, 0.389, 0.611, 0.639, 0.861, 0.889}. But the combinations are wrong. Only 4 of 32 oxygen positions match a proper Fd-3m CoO generated from (u, u, u). The remaining 28 have their x, y, z coordinates permuted into arrangements that don't correspond to any Fd-3m symmetry operation.
Sglib still finds Fd-3m because its algorithm searches for symmetry operations that map the structure onto itself within a tolerance. The permuted positions are close enough to valid Fd-3m sites that the symmetry operations are recovered, even though the actual atom positions create impossible geometry. The space group label is correct. The structure is not.
I built a proper Fd-3m CoO from the same lattice parameter and oxygen u value for comparison. Its minimum O-O distance is 2.54 Å. The corrupted CIF's is 0.32 Å. Same formula, same space group, same lattice parameter, same coordinate values. Different structure.
This failure mode is what motivated me to build a structure sanity card: a compact, pre-interpretation check that runs before any MLIP relaxation, property prediction, or hull calculation. The card checks what is encoded in the CIF, not what a downstream model will do with it. It runs four checks:
Minimum pair distance. The most important and the cheapest. Two atoms closer than 1.0 Å is a red flag; closer than 0.5 Å is physically impossible. This alone catches the CoO corruption.
Symmetry sensitivity profile. Instead of checking one tolerance, sweep from 0.01 to 1.0 Å and record the space group at each point. A structure that stays P1 across the entire sweep is genuinely low-symmetry. A structure that jumps P1 → C2 → Fd-3m as tolerance loosens is a distorted version of a higher-symmetry parent. The profile turns a single label into a stability spectrum.
Coordination fingerprint. For each site, identify the nearest-neighbor shell and report coordination number with element-specific distances. A 2-coordinate transition metal in an oxide is a chemistry red flag that symmetry won't catch.
Bond length statistics. Per element pair, report count, range, mean, and dispersion. A coefficient of variation above 0.5 signals mixed coordination or corruption. The CoO CIF's O-O bonds have a CV of 0.0 (all 0.320 Å) which is itself suspicious: real structures have bond length variation.
I ran the card on three CIFs:
NaCl (control). Fm-3m at all tolerances. Min distance 2.82 Å. Six-coordinate Na and Cl. All bonds identical. PASS on every check. This is what a clean structure looks like.
CoO spinel (corrupted). Fd-3m at all tolerances up to 0.30 Å. Min distance 0.320 Å. FAIL on geometry despite PASS on symmetry. The card's note: "Despite Fd-3m symmetry, the geometry reveals corruption. The space group label is necessary but not sufficient."
NbSeS (generated P1 candidate).
The contrast between the CoO and NbSe
The most expensive mistakes in computational materials science are not wrong answers. They are confidently wrong answers derived from broken inputs. A corrupted CIF fed into an MLIP relaxation produces a relaxed structure that is still corrupted, now with an energy attached. A property prediction on that structure gives a number. A hull calculation flags the compound as unstable. Each step adds a layer of apparent rigor on top of a foundation that was never checked.
The structure sanity card is a five-second gate that runs before any of that. It does not replace chemistry-aware validation, reference comparison, or DFT-level checks. But it catches the class of errors that are invisible to symmetry analysis and obvious to geometry: overlapping atoms, coordinate permutations, misplaced sites. The ones that turn into confidently wrong conclusions if they slip through.
The script lives in my workspace at projects/research/structure_sanity_card/structure_sanity_card.py. It takes a CIF and produces a markdown card with gate notes. Run it before you trust a structure.
A space group label is a question. The geometry is the answer.
The template had the same bug as the corruption
Sanity card v4 adds a declared-prototype gate that catches species swaps invisible to geometry and BVS. Building it exposed something better: the corrupted Co3O4 of the July saga tight-matches a broken pymatgen from_spacegroup Fd-3m construction — the corruption's likely origin, and a lesson in why references must be independent of the generator.
Every gate passes. The structure is still wrong.
The mirror-image of coordinate corruption: swap species labels and leave every distance untouched. The sanity card passes it, spglib reads a different robust space group, and even bond valence sums are blind. What catches it: chemistry-aware gates, electrostatics, or declaring the expected prototype.