orthonym.rules.parent_correctness#

Note

Internal API. Names and behaviour may change between releases.

Parent-correctness scorer for a phase.

Scaffolds the 5th confidence factor (parent_correctness) in the candidate scoring pipeline. a phase wires this into FACTOR_WEIGHTS with weight 0.0 so the factor is computed and logged but does NOT influence selection (byte-identical safe by IEEE 754 + Python 3.7+ dict-order). a phase raises the weight after 80/20 train/test calibration to activate it.

REFERENCE SOURCE (, locked in 145.1-internal notes):

OPSIN round-trip of the reference name. The only non-circular option: - Option A (chosen): OPSIN parses the reference name -> reference SMILES.

OPSIN is the inverse of Orthonym; reference names from ChEBI / PubChem / OPSIN self-test are external ground truth when they parse.

  • Option B (rejected – a phase’s work): a separate rule-based selector would pre-empt a phase.

  • Option C (rejected – too narrow): hand-curated parent map covers only the 500-compound opsin_selftest corpus.

EXTRACTION PIPELINE (, – locked from RESEARCH):
E1: regex parent-token + OPSIN re-parse + RDKit substructure match +

canonical-rank tiebreak. Pure Python + subprocess + RDKit; no Java<->Python bridge dependency. Verified on 6/9 test cases; remaining 3 fall back to 0.5 (no-decision = safe).

THREAD-LOCAL I/O (, locked):

Module-level _pc_context = threading.local mirrors the established coverage_scoring._confidence_store pattern at coverage_scoring.py:404. Benchmark runners call set_reference_name(name) BEFORE orthonym.name(smiles). Production callers (no reference set) immediately return 0.5 with zero OPSIN cost.

INVARIANT (security threat T-145.1-01 mitigation):

Production code path NEVER invokes OPSIN subprocess. Scorer.score short-circuits to 0.5 when _pc_context.reference_name is None (the production default). OPSIN is invoked ONLY in benchmark mode when set_reference_name has been explicitly called by the benchmark runner.

FAILURE MODES (RESEARCH – all return 0.5 no-decision):
  • OPSIN can’t parse reference name

  • Parent token regex returns empty

  • OPSIN parses parent token to invalid SMILES

  • Substructure match returns 0 hits (ChEBI noise)

  • Substructure match returns >1 hits -> canonical-rank tiebreak

  • OPSIN CLI subprocess timeout (caught)

  • _pc_context.reference_name is None (production path)

  • candidate.parent_atom_indices is None (handler didn’t report)

orthonym.rules.parent_correctness.set_reference_name(name)#

Set the reference IUPAC name for the current naming call.

Call BEFORE orthonym.name(smiles) in benchmark runs. Pass None to clear. Production callers (orthonym.name in REPL/library use) MUST NOT call this – leaving _pc_context.reference_name unset preserves byte-identical confidence values and avoids OPSIN subprocess cost.

orthonym.rules.parent_correctness.clear_reference_name()#

Clear the thread-local reference name (idempotent).

orthonym.rules.parent_correctness.opsin_reference_mol(ref_name)#

OPSIN-parse the FULL reference name once -> reference RDKit mol.

a phase SCORE-03 (A1 strategy, internal notes §A1 OPSIN-Cost Prototype): the per-node scorer parses the reference name ONCE per compound, then does RDKit fragment-submol matching per node (NOT one OPSIN call per node). Returns None on any OPSIN/parse failure (mirrors _opsin_to_smi’s caught-exception contract at:135-137). Reference names come from trusted corpora; OPSIN runs on STDIN (no shell), OPSIN_TIMEOUT=10.0.

orthonym.rules.parent_correctness.match_token_atoms_in_mol(token, input_mol)#

OPSIN-parse a parent-stem/fragment token and substructure-match it into input_mol, returning the matched atom-index set (or None).

a phase SCORE-03: the reusable per-node generalization of the atom-alignment step (extracted verbatim from the old inline body of _extract_reference_parent_atoms). 0 hits -> None; >1 hits -> CanonicalRankAtoms(breakTies=True) deterministic tiebreak (load-bearing per RESEARCH Pitfall 4 — set-order non-determinism caused a real a phase byte-diff); any failure -> None. OPSIN runs on STDIN via _opsin_to_smi (no shell, OPSIN_TIMEOUT=10.0).

class orthonym.rules.parent_correctness.ParentCorrectnessScorer#

Bases: object

Computes the parent_correctness factor for a candidate name.

Returns:

1.0 if candidate’s parent atoms match OPSIN-extracted reference parent 0.0 if mismatch 0.5 on no-decision (any failure mode – see module docstring)

Production callers (no _pc_context.reference_name set) immediately return 0.5 with zero OPSIN cost. Benchmark runners that have called set_reference_name pay one OPSIN parse per scored candidate.

static score(candidate, mol)#

Score a single candidate against the thread-local reference.