Skip to content

Put the ranks in a table, lint name endings from it, and read a null rank as none - #146

Merged
handrews merged 5 commits into
mainfrom
claude/phylogenetics-code-review-55ca0c
Oct 23, 2026
Merged

handrews merged 5 commits into
mainfrom
claude/phylogenetics-code-review-55ca0c

Conversation

@handrews

Copy link
Copy Markdown
Owner

data/ranks.yaml is now the rank vocabulary: the formal ranks in order,
as the data writes them, and the informal words flagged as such; it also
holds the suffix lint's rules (the ending a rank expects, the ranks an
ending expects, the year from which a name is checked) and the names the
lint lets pass, each with a note. phylohist/ranks.py reads it at import
for the constants both sides use, a load reads its own copy into a
RankTable the corpus carries, the schema's rank enum is held equal to
it by a test, and the loader errors on an exception that names no record
or a record at another rank. The old _check_rank, with its two loops,
46 inline exception names and a skip of every rank variant by its key,
goes: the lint checks records above the genus group from 1900 on, in
both directions, passes over another spelling, a gender form and a
vernacular form (a new Kind.suffix_checked flag), and checks a Latin
spelling and a rank variant at their rank. A superfamily accepts -acea
before 1999 and -oidea always; -oidea itself implies no rank, since
echinoderm classes end in it. Seven exceptions survive the cut in
data/, one more in the frozen test corpus, which has its own copy.

A record's rank: null means the source prints no rank word and no
cladistic term, and the code now reads it as none: the loader no longer
substitutes Unranked, which leaves the vocabulary (a modern unranked
clade is Clade), and the three unnamed Müller 1854 groups written with
it become null. The claims and the names index carry rank: null for
those records and their spellings (24 claim lines, 10 rows), headings
and labels print the name without a rank word, a placeholder still reads
"Unnamed unranked", and resolve_name(rank='unranked') finds them. The
open-nomenclature checks treat a record with no rank as unknown, and a
mineral, which has none, as no species-level name.

handrews and others added 5 commits October 22, 2026 14:14
Beside G8: what a null rank means and how the code reads it, Clade in
place of Unranked, the table as the curated vocabulary with section kept
until C6, and the 1900 cut for the suffix lint with its exceptions held
in the table.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The roadmap note said non-derivative records; a spelling derivative is
the only kind the lint skips, and an altRankOf record is checked at the
rank it declares.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…rank as none

`data/ranks.yaml` is now the rank vocabulary: the formal ranks in order,
as the data writes them, and the informal words flagged as such; it also
holds the suffix lint's rules (the ending a rank expects, the ranks an
ending expects, the year from which a name is checked) and the names the
lint lets pass, each with a note. `phylohist/ranks.py` reads it at import
for the constants both sides use, a load reads its own copy into a
`RankTable` the corpus carries, the schema's `rank` enum is held equal to
it by a test, and the loader errors on an exception that names no record
or a record at another rank. The old `_check_rank`, with its two loops,
46 inline exception names and a skip of every rank variant by its key,
goes: the lint checks records above the genus group from 1900 on, in
both directions, passes over another spelling, a gender form and a
vernacular form (a new `Kind.suffix_checked` flag), and checks a Latin
spelling and a rank variant at their rank. A superfamily accepts -acea
before 1999 and -oidea always; -oidea itself implies no rank, since
echinoderm classes end in it. Seven exceptions survive the cut in
`data/`, one more in the frozen test corpus, which has its own copy.

A record's `rank: null` means the source prints no rank word and no
cladistic term, and the code now reads it as none: the loader no longer
substitutes `Unranked`, which leaves the vocabulary (a modern unranked
clade is `Clade`), and the three unnamed Müller 1854 groups written with
it become `null`. The claims and the names index carry `rank: null` for
those records and their spellings (24 claim lines, 10 rows), headings
and labels print the name without a rank word, a placeholder still reads
"Unnamed unranked", and `resolve_name(rank='unranked')` finds them. The
open-nomenclature checks treat a record with no rank as unknown, and a
mineral, which has none, as no species-level name.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The schema allows `sensu: extenso` and Bather 1900 prints it on
Blastoidea, but the listing's mark table had no entry, so the Bather
listing raised a KeyError. The table now covers every value the schema
allows, and a test holds the two equal.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@handrews
handrews merged commit e08368b into main Oct 23, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant