orthonym.rules.terminal_fragment#

Note

Internal API. Names and behaviour may change between releases.

Phase B: the TERMINAL FRAGMENT namer – the complete-by-construction fallback that stands where a declining producer used to DROP a substituent.

Why this module exists#

Phase A measured that 132 of the 162 largest-class abstentions (81.5%) are silent ATOM DROPS, median -8 heavy atoms, and that they are multi-blocked at the code site: mean 2.69 distinct producer-refusal codes per row, best single-site fix 10/132 (8%). All 17 substituent_skip sites continue when a narrow producer declines a fragment, which removes that fragment’s atoms from the name; because selection is first_applicable at pool size 1, each skip is terminal and

then correctly rejects the atom-short name.

So the lever is not a fix list. It is one fallback that always accounts for every atom – the generalisation of the doctrine rules/terminal_ring.py already states: a table miss degrades to an UGLIER name instead of a refusal (the contributor guide a project rule, clause).

Contract#

terminal_fragment_name returns a substituent prefix token accounting for EVERY atom in frag_atoms, or None. It returns None – never a partial name – when the fragment is out of the implemented scope, when an element has no admitted morpheme (Table 1.5 is CLOSED, so fail-closed is the only sound design), or when the result fails its audit. It never raises: 17 call sites depend on it degrading rather than crashing.

This is the best-effort tier. The backbone choice is deterministic, NOT the

seniority cascade: a deterministic-and-complete name beats a

PIN-optimal-or-absent one here, and tier labels express preference, never correctness.

orthonym.rules.terminal_fragment.MAX_FRAGMENT_ATOMS = 40#

a bound past which a systematic name is neither useful nor cheap to audit.

Type:

Mirrors terminal_ring.MAX_CAGE_ATOMS’s intent

class orthonym.rules.terminal_fragment.TerminalFragmentName(name, numbering, basis, atoms)#

Bases: object

One audited terminal fragment name.

name the emitted substituent prefix token (‘2-oxabutyl’). numbering atom idx -> backbone locant, the SAME map the name was

spelled from (never re-derived), so a consumer can place further locants consistently.

basis which generator produced it: ‘chain’ (this task), later

‘ring’ or ‘composite’.

atoms every fragment atom the name accounts for. The completeness

invariant is atoms == frozenset(frag_atoms); it is asserted before returning, because an atom-short name is exactly the defect this module removes.

name: str#
numbering: Dict[int, int]#
basis: str#
atoms: FrozenSet[int]#
orthonym.rules.terminal_fragment.terminal_fragment_name(mol, frag_atoms, attach_idx)#

Name frag_atoms as a substituent prefix attached at attach_idx.

Returns None rather than a partial name for anything out of scope. Never raises.