orthonym.rules.parent_ranking#
Note
Internal API. Names and behaviour may change between releases.
a phase (P4-b): the Blue-Book-ranked parent-candidate SET.
WHY THIS MODULE EXISTS#
Production is early parent commit: each handler selects its own parent
internally and adds exactly ONE candidate to the pool, and the pool’s ranking
path is dead (selection_mode='first_applicable',
assembly/candidate_pool.py:135, and the module says so at :953-955). So
there was never a candidate set to filter — building the ranked set is the work.
See internal notes Part A1/A3 and Part G.
WHAT THE BLUE BOOK ACTUALLY LICENSES (derivation Part B1 + B1a)#
There is no escape clause conditioning the choice of parent on whether a name for it can be constructed. Every / criterion is a property of the structure or of the candidate name string; nameability is never among them:
the Blue Book — SENIORITY ORDER FOR PARENT STRUCTURES — “When there is a choice, the senior parent structure is chosen by applying the following criteria, in order, until a decision is reached. These criteria must always be applied before those applicable to rings and ring systems (see and to chains (see.”
the Blue Book — Selection between a ring and a chain as parent hydride — “Within the same heteroatom class and for the same number of characteristic groups cited as the principal characteristic group, a ring is always selected as the parent hydride to construct a preferred IUPAC name. In general nomenclature, a ring or a chain can be the parent hydride.”
Consequently a fall-through to a lower-ranked parent is never a PIN. Its correct status is fixed by:
the Blue Book — INTRODUCTION — “… Preferred IUPAC names are generated under the condition that the name of the parent structure and the names of all or part of components are preferred IUPAC names. When this condition is not fulfilled and when the names of components are acceptable for general nomenclature, the resulting names of the compounds are acceptable only for general nomenclature.”
PIN status is therefore conditional and compositional. A rank>0 emission is a
general IUPAC name (the Blue Book) — T3/T4, never is_pin: True. namer.
name_tiered already enforces that for every source == 'general_engine'
emission; record_parent_fallthrough makes the reason auditable rather than
merely correct.
But tier 2 is not the floor. the Blue Book marks discarded names not, and those
are “no longer recommended” — emitting one is an accuracy defect, not a
label. is_bluebook_discarded_name is the fail-closed veto for that.
CASCADE SHAPE, AND WHY IS NOT A CROSS-CLASS TERM HERE#
applies only “If the criteria of through … do not effect a
choice” (the Blue Book). For a ring-vs-chain pair always effects a
choice (ring wins, the Blue Book “always”), so the cross-class (a)–(l) list
can only ever fire within a class — where both existing scorers already
implement it (ring_system_score [27]/[28]; chain_score elements 3/4).
That is why this module needs no new comparator, and it is a derivation
result, not an omission.
Ranking key (all terms “lower is senior”, so sorted ⇒ most senior first):
- k0 -pcg_count (the Blue Book) max principal-characteristic
groups — precedes everything, ring or chain
- k1 -senior_atom_rank (the Blue Book) senior skeletal atom, in
‘s OWN element order (N>P>…>O>S>…>C)
k2 0 ring / 1 chain + (the Blue Book) ring always wins k3 within-class score rings: (a)–(g) then type then
(a),(b) —
ring_system_score, verified BB-faithful (derivation Part H1). chains:chain_score’s order (Part H2).
- k4 structural tiebreak alphanumerical order is the Blue Book’s own
last resort (the Blue Book); the chain scorer already applies it (
chains._p45_alpha_key). This final term makes the order TOTAL using RDKit canonical ranks, which are invariant to SMILES spelling — never atom-input or set/dict iteration order (determinism_newmust stay 0).
⚠ FOUR DISTINCT ELEMENT SEQUENCES (derivation Part B8)., (c),
(g)/(f) and (c) are four different orders; sharing one
table is a correctness bug. This module uses P_44_1_2_ELEMENT_RANK for k1
only — that table implements and nothing else.
RANK 1 IS THE INCUMBENT, BY CONSTRUCTION#
Rank 0 of the returned list is always the parent production already committed to
(select_principal_ring_system / features.principal_chain). That makes
the fall-through purely additive: it can only ever try parents that today’s
code never reaches, so best-effort output is byte-identical whenever rank 0
still passes its gates, and the PIN path never runs this code at all
(general_fallback defaults False, namer.py:1815).
- class orthonym.rules.parent_ranking.ParentCandidate(kind, atoms, rank, key, is_incumbent)#
Bases:
objectOne candidate parent structure, with its Blue-Book rank.
atomsis sorted for a ring system and ordered/oriented for a chain (the chain’s numbering direction is part of the candidate).rank0 is the incumbent — the parent production already chose.- kind: str#
- atoms: Tuple[int, ...]#
- rank: int#
- key: Tuple[Any, ...]#
- is_incumbent: bool#
- orthonym.rules.parent_ranking.is_bluebook_discarded_name(name)#
True if
nameis one the Blue Book marksnot(the Blue Book).Exact match over the lowercase/whitespace-collapsed name, against the corpus extracted by
scripts/extract_bluebook_not_corpus.py. Exact-only is deliberate: this predicate may only ever suppress an emission, so a substring or prefix rule (which could veto a correct name) is unacceptable while a miss (the veto not firing) is merely a known limitation.
- orthonym.rules.parent_ranking.enumerate_parent_candidates(mol, features)#
All ring systems and all skeletal chains — NO nameability pre-filter.
Returns
(ring_systems, chains, n_chains_dropped). The Blue Book’s cascade never consults nameability (derivation Part B1), so a candidate is dropped here only for combinatorial reasons, and the count is returned so the caller can log it rather than let a silent cap read as full coverage.
- orthonym.rules.parent_ranking.rank_parent_candidates(mol, features)#
The Blue-Book-ranked parent-candidate set, most senior first.
Rank 0 is the parent production already committed to (see the module docstring); ranks 1..N are the candidates today’s code never reaches, ordered by the cascade with a spelling-invariant final tiebreak.
- orthonym.rules.parent_ranking.features_for_candidate(features, candidate)#
A shallow features copy whose parent is
candidate.The three ring producers all resolve their parent through
select_principal_ring_system(mol, features.ring_systems), which returns its single element verbatim when the list has length 1 (ring_selection.py:785-786) — so restrictingring_systemsis enough to steer them, with no producer change at all. The chain producer readsprincipal_chain/chain_is_parent/atom_to_locant.Returns
featuresitself for the incumbent, so rank 0 is byte-identical.