RDKit dependencies and reader qualification

This reference records the dependency decisions and successive qualifications for the isolated RDKit worker. Early sections describe the evidence available when the candidate was selected; later sections record native-reader qualification. For supported inputs today, use the scientific guide.

preparation.in declares the separate RDKit closure for SMILES embedding and structure-file reading. It does not change inference.in, its lock, or the qualified prediction image. The existing package owner stages and applies this closure through make packages/preparation/lock/stage NETWORK_INTERFACE=YOUR_INTERFACE and make packages/preparation/lock/apply STAGE=lock.ID. Review the complete preparation.lock and preparation-advisories.json pair before applying it. Application validates the selected input filenames and hashes as well as the lock hash; an inference report cannot authorize preparation outputs.

The preparation lock was staged and reviewed on 2026-10-18; its three wheels were downloaded and independently verified offline that day. No runtime was qualified at acquisition time. Lock staging records PyPI exact-version advisory metadata; that is not a complete native-code audit. An applied lock alone does not authorize exposing every RDKit reader to uploads.

Candidate and unresolved native-parser evidence

Sources inspected on 2026-10-18:

The unresolved V3000 finding matters because uploads are untrusted native-parser inputs. Qualification must establish a fix or assess the exact candidate in an isolated worker before enabling that path. The evidence neither establishes that every V3000 file fails nor proves this wheel safe. No reproducer has been fetched or run. The repository's plain XYZ reader needs only element symbols and positions and does not call this RDKit parser. SMILES generation and the remaining readers still need their own bounded runtime tests and release admission.

Resolved closure review, 2026-10-18

The applied receipt records RDKit 2026.9.1, NumPy 2.5.4 and Pillow 13.0.0, checked at 2026-10-18T11:51:06.666100+00:00. Its lock SHA-256 is ea5c3e669a64ee07f3d4c87a6b003eb9e511103b70891b47ecb3e3c0a4fd51ea. The three exact-version PyPI responses contain no advisory entries. Preserve that scope: the RDKit native-parser record above is not negated by this receipt.

Additional primary-source checks:

RDKit workers use the complete locked dependency closure, including Pillow. Native molecular readers and conformer generation have separate behavioral checks described below.

Preparation wheels live directly in the selected WHEELHOUSE root, acquired with make packages/preparation/wheelhouse WHEELHOUSE=/absolute/cache/root NETWORK_INTERFACE=YOUR_INTERFACE and verified offline with make packages/preparation/wheelhouse/check WHEELHOUSE=/absolute/cache/root. Acquisition grants that root writable to publish complete files without replacing existing files; checks select only compatible, hash-locked wheels and installers read private copies offline. There is no default cache path; omitted selections prompt on the terminal. Preparation uses no Uni-Core source. Unrelated files in the shared root are not copied into its private image capture. See the shared-pool workflow.

The verified CPython 3.12 Linux x86-64 wheel bytes are:

These identify retained distribution bytes, not executed imports or a qualified SMILES/file-reader worker. No package installation was performed during acquisition.

Advisory recheck before runtime installation, 2026-10-19

Primary-source rechecks retained the candidate versions and the V3000 restriction. The rendered OSV-2022-675 record still lists the selected RDKit release as affected without a fixed event; exact-version PyPI metadata does not negate that native-parser report. The NumPy maintainer index still provides no published-advisory evidence, rather than a universal safety claim.

Pillow's maintainer index additionally lists XBM regular-expression denial of service, GIF open CPU exhaustion and zero-size rank-filter crash. Each identifies 13.0.0 as patched. These references were consulted to check the complete retained closure before offline installation; the runtime import check does not parse image files or enable any untrusted molecular-reader route.

Offline import evidence, 2026-10-19

make test/integration/rdkit-runtime owns a temporary, offline dependency check. It captures the lock and only its selected compatible wheels, installs the verified copies with hashes enforced into a virtual environment without pip, and runs isolated Python outside the checkout. The expected package list comes from the existing lock parser. No separate version table or bootstrap-package exception list is maintained. Native RDKit, NumPy and Pillow extension origins must lie inside that environment.

Three integration checks passed with Python 3.12.12, linux-x86_64, in the explicitly selected cached checker image sha256:9164d380c00bf0e013d44357cafb03d4b1f64570a93105f74ac4b85b66cf1b49. That was alternate-image import evidence at commit 806d7f9; the maintained target then could not start because its pinned Debian Python base was missing locally. No fallback is implemented. Four focused launcher/guard checks, changed-file lint/format and existing silent-default scanners also passed. The integration checks initially failed before installation for missing native packages, a different distribution set and use of the base interpreter.

This does not qualify the canonical worker image, a native molecular parser, SMILES generation or any public Upload route. The V3000 restriction above remains.

Canonical Debian base follow-up, 2026-10-19

After committing the explicit bootstrap target as 5062cf3, make packages/base-images/python/download returned zero and provisioned docker.io/library/python:3.12.12-slim-bookworm@sha256:593bd06efe90efa80dc4eee3948be7c0fde4134606dd40d8dd8dbcade98e669c. Local inspection reported image ID sha256:9cb180cb36bd45dc786105b834d3cb5f3b1d69a6a63c79ca10fc64f108aa649a, linux/amd64, and the same registry digest. This authorized bootstrap used Docker's default routing, with no forced interface binding; the reproduction prerequisites record that bootstrap exception.

The maintained make test/integration/rdkit-runtime then returned zero in that base: all three integration checks passed with Python 3.12.12, linux-x86_64, and pip reported no broken requirements. Installation used only the retained, hash-verified wheel closure in temporary container storage with no network. This qualifies those locked imports in the canonical base. It does not build or qualify molecular-reader behavior, exercise molecular files or SMILES, or enable public Upload submission. V3000 remains blocked pending its own decision.

Built geometry runtime image, 2026-10-19

After commit 2bab418, make geometry/image/build returned zero using the same retained wheels and pinned Debian base, with build networking and implicit pulls disabled. The recorded and inspected linux/amd64 image is sha256:be4358dd385b280723831950e527e44a87de4ee49afa9020ef8e7e8929bd3bb3 (370,977,650 bytes). Its io.nmrnet-repro.geometry-inputs label is sha256:821eb1a070de3c92a996e004a2353d1e43974e76754ed6113ff98d44bd395e96, identifying the committed Docker input inventory. It is checked before publishing the image record and before launching a test. Unrelated commits leave that inventory unchanged; a modified lock, Dockerfile or installed-tool input requires a rebuild.

make test/integration/rdkit-worker returned zero: all three installed-runtime checks passed in the recorded image. The maintained mol-reader lane then ran 14 direct reader checks using this installed closure with no package installation or network. Those checks cover supplied V2000 coordinates, preserved atoms and order, explicit unit conversion, bounded private native reasons, and pre-native rejections including V3000. They do not qualify SDF/PDB/MOL2, SMILES generation, the worker protocol for MOL, or Upload/interpreter/API submission. The V3000 advisory restriction is enforced before RDKit import, not tested by entering its affected native parser.

MOL2 format authority and interpretation, checked 2026-10-19

Tripos, Tripos Mol2 File Format, SYBYL 7.1 (Mid-2005), original vendor manual hosted on a mirror:

Printed and PDF page numbers coincide in this 54-page edition. This table supports the listed mappings, not a universal rule accepting any suffix after an element. Accepting further bare element spellings through the existing element authority would be our declared extension. Ignoring graph/alternate-type/attribute sections would be a declared coordinate-only projection, not complete molecular semantics. This evidence supports that design choice; it does not itself prove implementation, runtime behavior, scientific accuracy or RDKit compatibility.

Two explicit sulfur aliases have independent primary implementation evidence: MDAnalysis 2.9.0, SYBYL2SYMB maps both S.O/S.O2 and the commonly encountered S.o/S.o2 to sulfur; Open Babel 3.1.1, MOL2Format::ReadMolecule, lines 269-272 explicitly normalizes the two lowercase spellings to the uppercase forms. The manual's extracted text has uppercase O; a rendered page image was unavailable to the research tool, so no visual-verification claim is made. The independent tables agree with that reading. Accept these two exact aliases, not general case folding or arbitrary suffixes. The independent behavioral test covers all 27 documented dotted types and these two aliases. These sources support input interpretation, not a dependency on either library or runtime qualification.

MOL2 native-parser advisory provenance, checked 2026-10-19

The following records concern a possible native MOL2 route. They do not require using that route when the product only consumes supplied element/XYZ rows.

The exact pinned C++ file could not be retrieved through browsing during this review. A local source inspection used the older commit 40fe7ef6818b4d7695f74fe9fd177693e7f9886c (2025-11-18): Mol2FileParser.cpp. Its source-ID skipping, pseudo-atom handling and bond indexing motivate questions; they are not verified behavior of the retained 2026.9.1 wheel. This review acquired no new packages or source archives and ran no native parser or vulnerability probe.

SMILES generation evidence and design, checked 2026-10-19

The approved SMILES + conformer-count route is specified in note 003 and its tests-first sequence in note 016. Independent source review used the following primary RDKit references; these explain producer choices, not runtime proof:

Contained introspection of the existing pinned preparation image confirmed rdBase.rdkitVersion == "2026.09.1", EmbedParametersToJSON, timeout, maxIterations and the named ETKDGv3 preset. The preset exposes random seed -1 and timeout 0 by default; production generation must apply explicit admitted values. This inspection generated no coordinates and qualifies no input route.

The initial producer will return frozen generated requests and provenance, without forcing generated H or conformer IDs into supplied-file row/record fields. The existing batch/result owner remains authoritative when this value is bound to a Job. A shortfall retains actual IDs/coordinates privately and rejects the whole preparation, without reseeding or silently lowering the requested count. No disconnected-component exclusion was authorized in 003/016. Record actual generated positions without claiming an experimental relative pose for separate components; do not introduce a blanket molecular-equivalence gate here.

The pinned embedding implementation creates one timeout deadline at call entry, before fragment/conformer loops. This is a cooperative native-call deadline, not hard process termination. The wrapper description uses per-conformer/fragment wording; the tagged implementation controls this scope. The automatic attempt policy maps maxIterations=0 to ten times the embedded fragment's atom count. The producer requires an explicit positive attempt budget instead. Required settings are trusted composition inputs; no public tool may choose work budgets. The future worker binding must admit them against its fixed hard deadline before exposure.

EmbedParametersToJSON is a parameter serialization aid, not a promise to cover every effective choice. Retain explicit overrides and preset/runtime identity separately. GetFailureCounts returns aggregate counts for that embedding call, in the pinned EmbedFailureCauses enum order, not per-conformer reasons. A shortfall can include budget exhaustion; it is not classified as invalid molecular input.

Contained introspection of that same pinned serializer on 2026-10-19 showed property-tree string values: e.g. randomSeed="-1", timeout="0", numThreads="1", enforceChirality="true" and pruneRmsThresh="-1" for the untouched ETKDGv3 preset. The protocol compares any serialized explicit-setting fields against the admitted settings using that representation. Missing SDK fields stay missing; they are not invented from the request. This catches contradictory provenance without claiming that a self-reported snapshot proves native execution.

For each actual conformer ID, ROMol copy semantics allow retaining just that conformer with quickCopy=False, confId=id. AssignStereochemistryFrom3D then annotates atom/bond stereo from those generated coordinates. Its pinned implementation requires the 3D flag; replaceExistingTags=True invokes clearing/reassignment, avoiding stale CIP properties. Keep the original source atom/bond stereo separately and label the new annotations as generated-coordinate interpretations. RDKit-derived CIP labels are not experimental assignments or universal stereochemical validation. Source isotopes are retained even though the current model request schema carries only elements/coordinates; generated input has no enabled prediction route in this slice. Its later result/admission binding must preserve that distinction.

Native producer qualification, 2026-10-19: the maintained offline lane make test/integration/smiles-generator passes ten normative/adversarial tests against Python 3.12.12 and RDKit 2026.09.1 in the recorded preparation image. It generates all nine authored normative cases in tests/fixtures/preparation/smiles.json and separately checks atom maps, isotope retention, source versus generated stereo, plain-token parsing, explicit budgets, atom/count bounds and injected shortfall. Actual coordinates/settings are checked at the native call; no cross-version coordinate identity or prediction accuracy is claimed. This producer has no enabled Job, worker-channel or interpreter operation yet.