orthonym.assembly.t4_coverage#
Note
Internal API. Names and behaviour may change between releases.
universal coverage-by-construction namer (best-effort tier ONLY).
Reached only on the general-fallback best-effort recovery path – master
switch self._general_fallback in namer.py (its early return None
when that flag is False; general_fallback_unverified is a secondary,
narrower flag on the same path) – which itself only runs AFTER the
PIN/systematic path has already abstained. So this module can never change a
PIN emission; it only ever fills in where the PIN tiers were silent.
Produces an atom-complete, E1-certified name or None (clean abstain,
never a partial name). validation.e1_certificate.verify_certificate is
the atom-coverage certificate; downstream (OPSIN round-trip) is the
second half of the 0-wrong net, not a substitute for E1 here.
This module is the Task 2 SKELETON only: the control flow + the locked
_Candidate interface. Task 3 fills in _best_effort_candidate with the
real parent+substituents producer; Tasks 4-6 add the per-class cascade and
wire this namer into namer.py.
- orthonym.assembly.t4_coverage.last_t4_was_final_floor()#
True iff the most recent
name_t4_completecall in this context returned the final rung’s universal floor: no engine rung (the general engine with the perceived features or a feature override, the polyol rung) gave a candidate.
- orthonym.assembly.t4_coverage.last_t4_was_floor_substitute()#
True iff the most recent
name_t4_completecall in this context returned the universal floor standing in for a rung candidate that failed the full- InChIKey round trip (_prefer_verified_floor). Such a rung candidate is the mark of a degraded naming context (the recovery insidename; seenamer._try_besteffort_clean_general_fallthrough), where a clean context can still build the engine’s own verified name.
- orthonym.assembly.t4_coverage.reset_t4_floor_substitute()#
Clear the flags before a call whose producer may be replaced (tests stub
name_t4_complete), so a stale value is never read.
- orthonym.assembly.t4_coverage.name_t4_complete_candidate(mol, features)#
name_t4_completereturning the whole candidate (floor_substituteincluded). Same gates, same name.
- orthonym.assembly.t4_coverage.name_t4_complete(mol, features)#
Best-effort name for
mol, orNone(clean abstain).- Control flow (locked for Tasks 3-6):
Ask
_best_effort_candidatefor a name + its E1 proof object.No candidate at all -> abstain (
None).A candidate with no proof object (
result_obj is None) ships unchecked – E1 has nothing to verify.Otherwise the candidate must pass
verify_certificateor it is discarded – never patched, never shipped anyway.
Audit-coverage note (Fix 3a, final review): this returns a bare
str, not theGeneralEngineResultwith its atom->tokenbindings. So whennamer.pyships a name it CANNOT populate the binding-proof ledger –_record_binding_proofruns only on the engine’s own-nameelsebranch, never on the branch. That is an audit-coverage gap, not a correctness one: it is benign under the default (binding_proofoff), and T4’s 0-wrong net is E1 (proven internally here) + (the OPSIN round-trip in namer.py), neither of which needs the ledger. A follow-on wanting binding proofs would return the_Candidate(which carriesresult_obj) instead of a bare string.a phase Task 2b: ALSO requires
verify_spine(audit mode) to pass.verify_certificateproves only the flat atom partition (P1’s job); the binding spine additionally proves bond totality (P2), token-span anchoring (P4/P5) and arity (P6) – axes E1 cannot see at all (a name whose bindings silently re-fragment a ring, e.g. spelling cyclohexane as two disjoint propyl halves, passes E1 outright).mode="audit"stays the base mode (never “strict” here): a blanket strict flip would ALSO change P2’s bond-linkage inference policy and P5/P6’s unrelated unproven-codes severity, none of which this task’s scope covers.allow_charged=Falsematches theverify_certificatecall above so the two proofs never disagree about scope. A spine failure voids the candidate exactly like an E1 failure does – no new control flow.a phase Task 4:
escalate=STRICT_STEREO_CHARGE_AXESpromotes JUST the P8 stereo axis and P3’sCHARGE_UNVERIFIEDto error severity, on top ofmode="audit"– the coverage certificate’s stereo axis was shipped audit-only in Task 3 (findings recorded, ok never affected); the Task 4 diagnostic re-scan found 0 remaining false positives and 0 genuine stereo drops, so this makes it enforcing.allow_charged=FalsemeansNET_CHARGE_OUT_OF_SCOPE(unconditional “error”, not mode/escalate- gated) already voids any nonzero-net-charge candidate reaching this point regardless of this promotion; what newly blocks is a ZWITTERION (net charge 0, but individual atoms charged) whose charges no producer threaded throughcharge_atom_ids– measured byte-identical on a dev split best-effort (see the Task 4 report).Task 2a first wired this and measurably false-voided 3 correct, OPSIN-round-tripping a dev split rows via a pre-existing P6 (
token_arity) false-positive on replacement-nomenclature substituent tokens; that bug is fixed (Task 2b,name_morphemes.py::_evaluate’s multiplier short-circuit now also skips zero-atom REPL segments) and the a dev split best-effort before/after re-measurement is BYTE-IDENTICAL emit/rt_exact – see internal notes.
- orthonym.assembly.t4_coverage.name_prefix_order_fallback(mol)#
The universal floor’s name of
molwith its parent’s prefixes cited out of the order, orNone.The last resort of the best-effort tier for a molecule it would otherwise not name (
namer.Orthonym._maybe_prefix_order_fallbackis the only caller, and it adds the checks that make a shipped name the input’s): the round trip (OPSIN’s SMILES read by RDKit) can depend on the citation order of the prefixes, so a floor name in the order (the Blue Book order) can fail at the stereo layer although its descriptors are right – seeuniversal_substituent._prefix_order_fallback. A name is returned only when that rung built it: the -ordered spelling failed at the stereo layer only and this spelling reads back to the input’s full InChIKey. Such a name breaks on purpose and is never a PIN. Fail-closed: any error returnsNone.