First slice: contained upstream NMRNet++ inference baseline

Dated design and evidence record. Original wording, line order and historical source identities are preserved; use the current guides for operation.

Record sections
First slice: contained upstream NMRNet++ inference baseline
Date: 2026-10-13
Status: complete 2026-10-14 for the contained CPUfloat32 fold-0 H/C reference.

Purpose
-------

Establish a reproducible H/C inference baseline from the pinned upstream code
and released artifacts. The following slice can compare its direct prediction
adapter against this reference. This slice does not implement the NMR API
provider, a user-facing result schema, a direct SMILES adapter, or a persistent
runner.

The fork is the NMRNetplusplus submodule, currently pinned to
3ba8b9c2f3d0a390d00685d238618345c6ab24d7. Necessary compatibility fixes belong
in that fork and require a deliberate submodule update here. Preserve upstream
scientific behavior while establishing the reference.

Precedents
==========

Use the existing implementations as templates. The paths below refer to these
inspected revisions, not moving default branches:

SECS revision 34f5915c1534278bbf61b4c6592afa44cf94ab08:
https://github.com/numpde/secs-repro/tree/34f5915c1534278bbf61b4c6592afa44cf94ab08

- secs-repro/make/packages.mk and containers/packages/: dependency locks,
  wheelhouse preparation, and offline image builds.
- secs-repro/containers/checkpoint/ and tools/extract_checkpoint.py: contained,
  bounded artifact preparation.
- secs-repro/tools/docker.sh and tools/bound_http_proxy.py: interface-bound
  HTTP(S) transport; this repository contains the proxy and requires an interface.

NMRPeak revision f8055ab1065795fd46f8c1539e894cf9773f5495:
https://github.com/numpde/nmrpeak-repro/tree/f8055ab1065795fd46f8c1539e894cf9773f5495

- nmrpeak-repro/repository_checks/nmrpeak_weights.py and
  families/nmrpeak/weights.declaration.json: declared downloads, resumable
  partials, verification, and publication after verification.
- nmrpeak-repro/models/nmrpeak_hf_v1/releases/nmrpeak-zenodo-19122815-hf.json:
  artifact provenance and exact member identities, adapted only for NMRNet++'s
  actual requirements.

These are sibling repository paths, not runtime dependencies on sibling
checkouts. Adapt the required pieces locally. Do not copy their entire provider
or deployment frameworks into this slice.

Some NMRPeak targets invoke host Python. That execution choice does not apply
here: all repository Python, dependency operations, archive processing, model
execution, and tests must run in contained containers. Host Make/shell and Git
perform orchestration, path preparation, and version-control operations only.

1. Contained tooling and artifact acquisition
============================================

Introduce the smallest Make/script/container setup needed to acquire and
inspect the release. Follow the precedents' explicit image pulls and command
interfaces. Keep downloads, scratch data, weights, and results out of Git.

Read the pinned upstream scripts and inspect enough of the verified release
archives to select one compatible H and one C checkpoint configuration, with
their architecture arguments, dictionaries, scalers, folds, and prepared data.
Check solvent support for the selected configurations; broader variant coverage
is deferred. For solvent-aware models, record each selected record's raw solvent
and effective category: upstream maps CDCl3 to 1, DMSO-d6 to 2, other strings to
3, and a missing field to 0. Preserve those categories without claiming specific
solvent support for the pooled category. The README's availability claim is not
proof that each required file exists.

Record source record/version, archive name, size, and published checksum using
the acquisition precedent. Verify those before consuming archive members;
record SHA-256 identities of selected prepared files. A locally computed hash
records the selected bytes; it does not independently authenticate their source.

Download into dedicated staging. Inspect and extract selected members offline,
with bounded memory and output size. Reject unsafe member paths and incomplete
archives. Publish prepared artifacts only after successful verification, using
the precedent's staging/publication behavior. Preserve resumable partials and
refuse accidental replacement of existing verified artifacts.

Acceptance: truncated or modified archives fail verification; interrupted work
does not appear complete; required members are identified; selected extraction
cannot escape its output directory or overwrite an installed artifact.

2. One locked inference environment
==================================

Resolve the pinned upstream inference dependency closure, including Uni-Core,
using the contained lock and wheelhouse workflow. Check current advisories for
the exact proposed dependency versions before installation. Stage candidate
lock changes separately and apply them explicitly offline. Build the inference
image offline from the reviewed lock, verified packages, and declared source.
Pin base images by digest; record the built image's immutable ID or digest.

Choose one explicit device/dtype configuration from actual upstream requirements
and the available execution target. Establish that configuration first; do not
silently switch device or precision after a failure. Additional hardware lanes
are outside this slice.

Exercise the real imports and model construction before a full inference run.
Verify required dictionary/scaler/model pairing, including the release's ordered
token-to-index mapping and upstream special-token additions; matching vocabulary
size alone is insufficient. Require all atoms in selected examples to have
dedicated dictionary entries rather than unknown tokens. Account for missing and
unexpected checkpoint keys: upstream infer.py uses strict=False, which alone
does not establish a correct model load. Missing inference parameters or
incompatible shapes fail the baseline; allow only identified differences that
do not participate in inference. Explain necessary compatibility changes and
preserve numerical behavior.

Acceptance: after preparation, the image builds without network access, imports
the real inference stack, and loads the selected H/C models with all required
inference parameters present. Missing or ambiguous required artifacts remain an
explicit unresolved finding, not a guessed substitute or a successful baseline.

3. Small upstream H/C reference run
==================================

Upstream reads a complete valid.lmdb and has no small-sample selector. Derive
a small valid.lmdb in an isolated preparation directory by copying explicitly
selected records with valid labels for the chosen H or C task, preserving the
upstream record schema. Write and verify the matching valid_dbid.pkl with those
record keys in the chosen order: upstream otherwise creates or consumes that
companion implicitly. Record source archive/member, selected keys, and hashes
of both derived files. Preserve atom order, coordinates, solvent fields, target
masks, and labels. Verify copied records against the originals; do not invent
target labels to make the evaluation machinery run.

Choose records within explicit atom and token limits, recording those limits
in the invocation. Require that no selected record is cropped or truncated:
upstream CroppingDataset changes atoms and coordinates without changing the
aligned targets/masks. Keep hydrogen removal and conformer augmentation off for
this prepared-coordinate reference. This bounds the baseline to intact records
without adding an upstream cropping repair to the slice.

Invoke the upstream inference entrypoint with explicit arguments rather than
launching the training-and-evaluation script. Mount each matching
target_scaler.ss at the selected --saved-dir location. Retain upstream H/C
pickle outputs and identify their fields: atom_regloss already inverse-scales
the saved predictions. Verify the selected data/scaler's target units before
labeling them ppm. Do not apply the inverse transformation again.
Labels support the existing evaluation path; this is not yet the label-free
molecule interface.

Identify the checkpoint and fold for every result. First establish individual
checkpoint reference outputs. Inspect the upstream fold aggregation separately;
do not label an individual-fold baseline as an ensemble or choose the eventual
production aggregation policy by convenience.

Record submodule commit, immutable image ID/digest, dependency lock, artifact
hashes, arguments, example selection, device/dtype, effective hardware and
driver/runtime, predictions, and measured runtime and memory. Repeat on the same
execution target and compare every prediction after record/atom alignment
against an explicit tolerance justified by the runtime. Report the maximum
absolute difference and state any relative tolerance separately. Do not relax
tolerances merely to make a failed comparison pass.
Use a fresh result directory for each invocation: upstream overwrites its fixed
output filename. Retain and hash each run's output separately before comparison.

Acceptance: account for each run's selected records and expected selected-atom
counts, with finite H/C ppm predictions. Bind each prediction to its source
record and atom index using the batch record IDs and selection masks; verify
the per-record slices against source atom/target order, not just total counts.
Fail on omitted or duplicate records: upstream's iterator allows
invalid inputs to be skipped, so a zero process exit alone is insufficient.
The repeated run agrees within the stated tolerance. This proves reproducibility
on those examples, not general scientific accuracy, solvent performance, or
parity of a future adapter.

4. Container authority and executable proof
==========================================

Download/dependency preparation has explicit external network access and writes
only to dedicated staging/cache locations. It receives only needed public
declarations and source inputs. It cannot write the repository source tree.

Require an explicit command-line WLAN_INTERFACE=<interface> for every networked
acquisition, following the SECS interface-bound HTTP(S) proxy precedent.
Reject an omitted or unavailable interface; do not autodetect or fall back to
host routing. Keep proxy/tool execution contained. Docker daemon pulls are outside
the SECS wrapper's binding, so they must not silently bypass this requirement.
The contained proxy requires the explicit interface and binds outbound HTTP(S)
connections to it. Base images must already be available locally: the pull
targets refuse daemon downloads because this wrapper cannot bind those pulls.

Archive inspection/extraction, package installation into the final image,
inference, and ordinary tests run offline. Runtime containers use a non-root
identity, read-only root and inputs, dropped capabilities, no-new-privileges,
bounded scratch space, and explicit CPU/memory/PID limits. Set resource limits
before execution and adjust them explicitly using observed requirements.

No lane receives API credentials, home-directory mounts, an engine socket, or
unrelated repositories. Grant a selected device only to inference if required.
Host orchestration owns engine access. Build contexts exclude Git metadata,
private files, and undeclared local artifacts. Build-time network
and writable state are declared separately from runtime restrictions.

Check generated commands and inspect the effective running-container settings.
Exercise denied source writes and denied network access in offline lanes.
Confirm output ownership and cleanup of ephemeral containers/scratch. Preserve
verified downloads and results; do not introduce blanket cleanup commands.

Ordinary make test runs contained, offline checks with small synthetic fixtures:
corrupt archives, missing required members, unsafe extraction, interrupted
publication, and relevant launcher boundaries. Establish failing checks before
implementing the corresponding behavior. Real checkpoint loading and inference
belong to the explicit baseline lane, not the lightweight default suite.

Operator interface and delivery
===============================

Adapt familiar commands as their implementations become functional:

- make packages/base-images/pull
- make weights/download and make weights/check
- Package lock, wheelhouse, and image commands following SECS conventions.
- make baseline/prepare and make baseline/run
- make test

Keep preparation and execution explicit: baseline/run consumes prepared
artifacts and the built image without hidden downloads, installs, or training.
Provide a short README procedure sufficient for a clean recursive checkout.
The submodule is pinned; selected releases and images must also be identified.

Use three coherent implementation checkpoints: contained acquisition/tooling;
locked environment and prepared artifacts; working baseline and its evidence.
Each commit includes its focused checks. Commit and push meaningful completed
steps, keeping audit corrections with the step they correct.

Completion means a clean checkout can follow the maintained commands to
prepare the identified artifacts, build the image, and reproduce both upstream
H/C reference outputs. Once preparation is complete, the baseline reruns offline.
Update this note with observed artifact/model pairing and remaining limitations
when that evidence exists. Do not report this planned capability as implemented.

Implementation evidence (2026-10-13; partial)
===========================================

Contained acquisition and dependency preparation are implemented. Archive
downloads are resumable and individually selected with ARCHIVE; verification,
inspection, and selected extraction run offline. Extraction verifies the same
open archive it reads, bounds directory/member processing, rejects unsafe paths
and unsupported compression methods, and publishes without replacing an existing
prepared directory. Ordinary tests use synthetic fixtures inside the pinned
Python container.

Interface selection follows the SECS proxy precedent, with an explicit Make
command-line WLAN_INTERFACE required here. Both proxy and downloader run in
containers. Cancellation regressions cover signals before container creation
completes; wrapper cleanup removes only its recorded worker and proxy IDs.
This binds cooperating HTTP(S) clients, not arbitrary hostile client traffic;
DNS still uses the host resolver. Offline lanes use network=none.

The tooling probe verified non-root identity, read-only source/root, dropped
capabilities, no-new-privileges, CPU/memory/PID bounds, denied offline network,
and caller-owned output. Independent reviews covered acquisition, network
launch/cancellation, dependency lock application, and wheelhouse publication.

Release record 18232165 supplies three archives. Full archive verification is
required by this slice even though only selected members are consumed.
weight.zip verified against its published size and MD5 and yielded weight/dict.txt
(91 bytes; SHA-256
f4fafdbc445449c8f8ef613fee36c8ee7610e3c7c2766666635edc8d962ba134).
The data and checkpoint archives are not yet fully acquired or verified.
Their selection declarations remain provisional until verified extraction and
actual model/data compatibility checks succeed.
artifacts/release.json records the exact metadata and content URLs, archive sizes
and published checksums from https://zenodo.org/api/records/18232165.
artifacts/weight.selection.json, artifacts/data.selection.json and
artifacts/checkpoints.selection.json name members of those respective archives.
Those names were discovered by bounded remote ZIP-directory inspection; that
discovery did not verify the complete archives or qualify model/data pairing.
Subsequent verified extraction receipts bind consumed members to archive identity.

The candidate environment is Python 3.12.12, CPU float32, Torch 2.13.0+cpu and
pinned Uni-Core source. The applied hash lock has 59 packages. Its retained
exact-version PyPI advisory receipt reports no advisory entries; this is an
advisory check, not a complete security audit. Package acquisition, real image
build and imports have passed as detailed below. Model loading and repeated H/C
inference have not yet passed; no scientific baseline completion is claimed.
requirements/README.md records the pinned upstream dependency declarations,
local environment choices and exact advisory references behind these pins.

Audit execution deviation: one early dependency-lock audit invoked host Python
twice, contrary to the container-only rule. Importing package_lock.py wrote an
ignored __pycache__ file; no network transfer occurred. Those host executions
are not accepted as contained proof. The replacement audit passed in the pinned
offline, read-only, non-root container: the actual staged lock/report and all
input hashes matched, and temporary apply fixtures covered rejection before
writes and successful exact-byte application. Its local evidence is retained
in .work/qualification/development-20261014/lock-audit-contained.log.
The maintained launchers and ordinary test
lane do not require host Python.

The offline image/import and baseline/prepare launchers are implemented and
independently reviewed. Preparation preserves selected LMDB bytes and ordered
keys. Model preflight reuses upstream parsing/construction and rejects missing
or unexpected checkpoint keys. Output verification checks source atom/token/
label alignment and complete record coverage, retaining output hashes; repeat
comparison accepts explicit absolute and relative tolerances. At that checkpoint,
122 contained offline tests passed. These fixture checks do not replace real
LMDB/tensor, checkpoint, and repeated-inference execution evidence.

The maintained baseline/run launcher and retained execution/comparison receipts
are implemented and independently reviewed. At that checkpoint, full contained
make test passed 136 tests; the local execution log is
.work/qualification/development-20261014/baseline-tooling-tests.log.
Source attribution and the rationale for consulting the project's paper have
also been documented and independently reviewed. Prepared LMDB/tensor execution,
checkpoint loading and repeated H/C inference still await acquisition and
execution. Slice 001 remains in progress.

Real environment evidence: the maintained wheelhouse check, offline image build
and import check passed at repository revision
a757165b7914d003b329299b553a7bf66b731219. Their local logs and zero exit-status
receipts are .work/qualification/setup-20261014/wheelhouse-check.{log,exit},
.work/qualification/setup-20261014/image.{log,exit} and
.work/qualification/setup-20261014/imports.{log,exit}.
The image build ran on 2026-10-13 at 19:57:03-19:57:46 UTC; imports finished at
19:57:50 UTC. The resulting immutable image identity is
sha256:578b272ff63ee1d34b85f20d34ea659d9953528a4b61cd090f4db18186f3fd84.
A fresh independent contained probe confirmed Python 3.12.12, Torch 2.13.0+cpu,
no CUDA runtime, default float32, successful pip check and imports of torch,
unicore, uninmr and uninmr.infer. It also matched the image's embedded dependency
declarations to the checkout: inference.lock SHA-256
3abca8de5f3b3e18041bbab50e5caef1763c9bbb8801a1567574ba9ed30e80f5 and
unicore-source.json SHA-256
c58cad18b89a3db3358a6e1995b27287fd0b434e8ee3b37f4e26c87f72e39200.
That independent probe is recorded in the review transcript, not a saved local
receipt. This establishes environment construction/imports; the data and
checkpoint archives remain incomplete and no scientific baseline is qualified.

Peer correction - dependency identity: commit
3f0e4567f50dd1abf7322d26a578c735059fb6d9 makes baseline preparation and execution
compare both embedded dependency declarations with the checkout before scientific
imports. Uni-Core is built separately from the package lock, so checking the lock
alone could admit an image built from a different source declaration.
tools/baseline.sh owns admission against the files installed by
containers/inference/Dockerfile; tools/baseline_run.py records the consumed
requirements/unicore-source.json identity. tests/test_baseline_launcher.py covers
independent drift of either declaration and matching admission;
tests/test_baseline_run.py checks the retained source identity. These fixture
checks do not establish real checkpoint compatibility.

Peer correction - executed tool provenance: commit
b40e62da0400a2b1dbb2fa5289f8acdded6b6661 records the immutable image ID,
repository revision and actual byte size/SHA-256 of mounted Python tools.
Git HEAD and the image ID alone omit uncommitted bind-mounted tool changes.
tools/baseline.sh uses the same module list for read-only mounts and --tool-source
arguments; tools/baseline_prepare.py:execution_identity hashes those inputs
inside the container. Preparation retains this identity under execution in
provenance.json. tools/baseline_run.py retains the same fields in attempt.json
and successful complete.json, while its prepared_receipt hash links the original
preparation provenance without rewriting it. Dirty checkouts remain usable with
their actual tool bytes identified. Independent review found no further issues;
43 focused contained tests passed across tests/test_baseline_launcher.py,
tests/test_baseline_prepare.py and tests/test_baseline_run.py, including changed
tool bytes under unchanged commit/image identities and receipt linkage.

Peer correction - retained failure diagnostics: commit
bf94ca82c69db7db939f35fd9d2fb9258316666f adds one exception boundary in
tools/baseline_run.py:run after exclusive attempt-directory creation. Previously,
preflight and verification tracebacks escaped to the terminal after their local
log contexts closed. The runner now writes the traceback and exception chain to
an exclusively created failure.log, flushes and synchronizes it, then re-raises
the original exception. An OSError while retaining diagnostics adds a note to
that exception rather than replacing it. Admission failures and existing output
directories remain untouched. Independent review found no further issues and
all 11 contained tests in tests/test_baseline_run.py passed, including chained
preflight, output-verification and comparison failures without complete.json,
diagnostic-write failure and preservation of an existing failure log. Abrupt
termination cannot guarantee a retained log. This correction does not change the
existing possibility of an I/O failure after completion-receipt publication.

Peer correction - wheelhouse durability: commit
f4f9118feef5266bdc9caea72a45ddb04aa5894f makes tools/wheelhouse.py synchronize
verified payloads, its receipt and the staging directory before no-clobber
publication, then synchronize the destination parent. This follows the existing
tools/artifacts.py extraction order: atomic naming alone does not ensure
completed acquisition survives a machine crash. All 11 focused tests in
tests/test_wheelhouse.py passed in the pinned offline container. An independent
temporary-fixture probe also confirmed that a parent-directory synchronization
failure propagates, preserves the published verified files and emits no success
claim. These checks did not modify the real acquired wheelhouse.

Validation after these corrections: the maintained contained make test passed
all 144 tests with exit status 0 before the final comment-only correction.
The retained local execution log is
.work/qualification/development-20261014/peer-corrections-tests.log. Combined
independent review identified a stale completion comment; it was corrected and
the fresh recheck found no further actionable issues. These fixture regressions
do not replace the pending real prepared-data, checkpoint and repeated H/C
inference qualification.

Scientific reference: the pinned upstream README identifies this project's
paper, which is why it was consulted for the intended units and benchmark split:
https://github.com/numpde/fork-of-NMRNetplusplus/blob/3ba8b9c2f3d0a390d00685d238618345c6ab24d7/README.md#L4
The version consulted is Yongqi Jin et al., "From Human Labels to Literature:
Semi-Supervised Learning of NMR Chemical Shifts at Scale", arXiv:2601.18524v1,
26 January 2026: https://arxiv.org/html/2601.18524v1
Table 6 labels the H/C chemical-shift bounds in ppm; Section 4.1 states that
NMRShiftDB2 uses its predefined benchmark split. These support the intended
units and split convention. Correspondence with the selected release records
and scaler round trip still requires execution evidence.

Release and scientific qualification (2026-10-14)
================================================

The historical acquisition gaps above are now resolved. All three complete
archives passed their declared size/MD5 checks, and the selected extraction
receipts were independently rehashed before deserialization. Local evidence:
.work/qualification/20261014/{weight,data,checkpoints}-check.{log,exit},
members-check.{log,exit}, and .work/prepared/{weight,data,checkpoints}/provenance.json.
The data archive SHA-256 is
a6a23990cef1f0c28f835a4fdc9a5437d9d2f2bb13c758c07b7dc10c887c5b73;
checkpoints archive SHA-256 is
aba477d82049470366dd14088ec0fe03b2e9015c833c98d2dfa191d6aecfee2c.
The verified validation member data/nmrshiftdb2/All/valid.lmdb is 21,131,264 bytes,
SHA-256 a72e17e3c9293b5852ef8d493f4ede23eb8b5cd8ca8e4c827a9bd8072e6a3a04.
These identities replace provisional remote-directory discovery with verified
release bytes; artifacts/release.json and the selection files remain the
source declarations, rather than a second handwritten download manifest.

Maintained baseline/prepare passed at repository revision
6ee0fa1f02dc2838b696d8b17cc48523dd583969 with the immutable image recorded above.
Its provenance.json binds prepared files, original records and executed tool
bytes. Independent contained audit compared original serialized LMDB values,
ordered companion indices, bounds and dictionary: C keys 30/31 (hex) contain
40/27 atoms and 22 selected labels; H keys 35333738/35333739 contain 42/38 atoms
and 42 selected labels. Dictionary order is preserved, with the task appending
[MASK] at index 30, yielding 31 symbols. Evidence is retained under
.work/qualification/20261014/prepare.{log,exit,command,revision} and
preparation-independent-audit.{log,exit}; outputs are .work/baseline/prepared/.
The NumPy legacy-module warning emitted while reading upstream serialized
records is retained; it did not change the original record bytes.

Scientific review is retained in
.work/qualification/20261014/scientific_review.txt and its contained probe
scientific_probe.{py,sh,log,exit}. The probe rechecks release member hashes before
loading objects; its script SHA-256 is
91f9b0265d4019767540c710a49c1752ce859e7b4b3370cb065d0fae5a4d141b,
and its successful log SHA-256 is
6706934d3ea83bfb0016dc8ad1d31c22b2c32f83753f26fba9f06c74c4ae639f.
An initial diagnostic incorrectly assumed that StandardScaler preserved
Torch-input float32 during inverse_transform. That assertion failure remains
in scientific_probe.first.log. Inspection showed float64 inverse arithmetic
before upstream's final float32 cast; the corrected probe checked that actual
path against independent affine arithmetic. No fitted parameter or acceptance
tolerance was changed to accommodate the diagnostic correction.

The selected H/C fold-0 checkpoints are the configuration directories ending
20250930_033837 and 20251004_182236, respectively, named in
artifacts/checkpoints.selection.json. Each consumes target_scaler.ss from its
own configuration parent. Released infer.log arguments and independently read
checkpoint arguments agree on selected element, uninmr task, unimol_large,
atom_regloss_mae, Gaussian kernel, atom_descriptor=0, nmr_head and one output.
Both use 15 encoder layers, embedding width 512, feed-forward width 2048 and
64 attention heads; checkpoint token embeddings have shape 31 by 512. Model
preflight owns full checkpoint-key and exact ordered dictionary checks.
The release logs used GPU/FP16, seed 1, batch 64, eight workers and bounds
512 atoms/1024 tokens. The local bounded reference deliberately uses CPUfloat32,
seed 42, batch 1, zero workers and intact records within 128 atoms/130 tokens.
This does not assert numerical parity with the released GPU runs.

The scaler files contain sklearn 1.5.2 StandardScaler objects, loaded here by
sklearn 1.8.0. The emitted InconsistentVersionWarning is preserved. H mean/scale
are 4.679020224644767/2.647037530276721; C mean/scale are
98.16048755759934/51.332831732325104. Both have one feature and finite positive
scale. On all selected labels, transform matches (x-mean)/scale exactly;
Torch-input inverse_transform and final float32 cast match independently
computed affine arithmetic exactly. This qualifies these actual dense scaler
operations, not general cross-version estimator compatibility. No scaler was
refitted. Their loading and arithmetic authority is pinned upstream
https://github.com/numpde/fork-of-NMRNetplusplus/blob/3ba8b9c2f3d0a390d00685d238618345c6ab24d7/uninmr/utils/data_scaler.py#L32-L54
and the installed implementation printed in scientific_probe.log, bound to the
image and dependency lock.

Ppm attribution uses a connected source chain: the pinned README identifies
both the paper and this release,
https://github.com/numpde/fork-of-NMRNetplusplus/blob/3ba8b9c2f3d0a390d00685d238618345c6ab24d7/README.md#L4
https://github.com/numpde/fork-of-NMRNetplusplus/blob/3ba8b9c2f3d0a390d00685d238618345c6ab24d7/README.md#L13-L16
and the previously consulted paper's Table 6 names H/C chemical-shift units as
ppm. The verified labels enter the paired scaler through
https://github.com/numpde/fork-of-NMRNetplusplus/blob/3ba8b9c2f3d0a390d00685d238618345c6ab24d7/uninmr/data/normalize_dataset.py#L31-L38
https://github.com/numpde/fork-of-NMRNetplusplus/blob/3ba8b9c2f3d0a390d00685d238618345c6ab24d7/uninmr/tasks/uninmr.py#L381-L383
and the saved predictions/labels receive exactly one inverse transformation:
https://github.com/numpde/fork-of-NMRNetplusplus/blob/3ba8b9c2f3d0a390d00685d238618345c6ab24d7/uninmr/losses/atom_regloss.py#L75-L76
Verified identity and the scalar round trip establish preservation of those
original label units. Ppm therefore relies on the documented release convention;
numerical ranges alone would not establish physical calibration. Release logs
refer to nmrshiftdb2_2018/All, while the shipped path is nmrshiftdb2/All. This
reference does not claim independent paper-testset identity or benchmark accuracy.

Before baseline execution, LABEL_ATOL=0.0001, ATOL=0 and RTOL=0 were declared in
.work/qualification/20261014/tolerances.txt. LABEL_ATOL permits arithmetic
rounding, not model prediction error. For float32 unit roundoff u=2^-24, a
conservative first-order allowance u*(4*abs(x-mean)+2*abs(mean)) covers casting
the standardized target, mean and scale plus multiplication/addition. Float64
standardization error is negligible at these finite magnitudes and nonzero
scales; the actual Torch-input inverse uses float64 and requires fewer float32
roundings. H labels span 0.31..7.54 and C labels 12.9..171.5. Maximum calculated
allowances are 1.5994382707994344e-6 and 3.2029326280689005e-5 ppm, respectively,
both below the predeclared 1e-4. Independently observed Torch-input scalar
round-trip errors were H 3.2424926743601645e-7 and C 3.4332275404835855e-6 ppm.
Exact repeated predictions are required for the same image/CPU/thread settings,
full loaded state, batch size 1, evaluation mode, fixed input order, and disabled
augmentation/cropping. Any difference requires investigation; these settings do
not promise bitwise equality across architectures or runtime builds.

Fold aggregation was reviewed separately. The upstream invocation runs folds
0 through 4 and then calls get_result.py in cv mode:
https://github.com/numpde/fork-of-NMRNetplusplus/blob/3ba8b9c2f3d0a390d00685d238618345c6ab24d7/script/infer.sh#L11-L28
That helper computes np.mean(np.vstack(all_predict), axis=0), retaining the last
fold's targets/tokens without checking record identity:
https://github.com/numpde/fork-of-NMRNetplusplus/blob/3ba8b9c2f3d0a390d00685d238618345c6ab24d7/uninmr/utils/get_result.py#L60-L96
The present reference uses fold 0 only. Future aggregation must establish
record/atom alignment before averaging; this slice establishes no production
ensemble policy and does not run the plotting helper.

The first maintained attempt, reference-20261014 at revision
6ee0fa1f02dc2838b696d8b17cc48523dd583969, failed before producing H predictions.
Python -m imported uninmr before Uni-Core processed --user-dir, triggering its
module-registration collision guard. The attempt, H/run-1/inference.log and
failure.log remain under .work/baseline/runs/reference-20261014/; outer evidence
is .work/qualification/20261014/run.{log,exit,command,revision}. Commit
dc09d448e3b747a98ec8c5787ec5ac4db308bc2c changes execution to the script path,
matching upstream script/infer.sh:16, without modifying the scientific model.
The focused independent check is retained as
.work/qualification/20261014/entrypoint-independent-review.{log,exit}.
The corrected attempt uses fresh ID reference-20261014-script; its successful
execution and independent runtime review are recorded below.

Completion evidence (2026-10-14)
================================

The corrected maintained run reference-20261014-script completed at code revision
dc09d448e3b747a98ec8c5787ec5ac4db308bc2c. Both preflights loaded all 47,593,795
parameters with no missing or unexpected keys. Four independent upstream script
processes exited zero. H produced all 42 selected predictions and C all 22;
all predictions were finite and both repeat comparisons had maximum absolute
difference zero with ATOL=RTOL=0. Actual label differences were H
3.2424926743601645e-7 and C 3.4332275404835855e-6 ppm, within predeclared
LABEL_ATOL=0.0001. Run evidence remains under
.work/baseline/runs/reference-20261014-script/; orchestration evidence is
.work/qualification/20261014/run-script.{log,exit,command,revision} and retained
container command/inspection/statistics files beside them.

The independent contained runtime audit passed and rechecked all four raw
outputs against original LMDB record/atom/token/mask/label identities, complete
coverage, finite values and repeated equality. Prepared files, model/scaler/log
members, declaration inputs and executed tool hashes remained unchanged. It
also confirmed actual container removal and caller-owned output. Its local
receipt is .work/qualification/20261014/runtime-independent-audit.{log,exit}.
Container-removal and output-ownership evidence is retained separately in
.work/qualification/20261014/runtime-cleanup-audit.log.
This audit and the separately documented scientific review close the execution
receipt's release/configuration and target-unit review items. The original
complete.json is preserved with its pending_review list: it records what the
execution itself established, while this note records subsequent qualification.

Recorded runtime was Linux x86-64, Python 3.12.12, Torch 2.13.0+cpu, CPUfloat32,
OMP_NUM_THREADS=MKL_NUM_THREADS=2, batch size 1 and zero data workers. The inference
container had two CPU quota units, 4 GiB memory with no swap, 64 PIDs, read-only
root/inputs, no network, dropped capabilities and no-new-privileges. End-to-end
runner elapsed time was 20.04145074400003 seconds. Recorded process-lifetime
RSS high-water marks were runner 1,111,948 KiB and waited children 1,139,532 KiB;
these are neither per-run values nor total container peak memory.

A compact public numerical reference is artifacts/reference-cpu-float32.json.
It contains 64 predictions with dataset index, original record key and atom index;
source_label_ppm is taken from the original preparation labels, not relabelled
rounded output targets. The file retains image/source/tool identities,
preparation and complete-receipt hashes, selected model/data/dictionary/scaler
identities, tolerances, comparisons and runtime/resource facts. Its source links
and rationale explain the ppm convention and separate fold averaging. It was
exported from hash-checked successful receipts in the pinned offline container;
local export_reference.{py,sh,log,exit} under .work/qualification/20261014 retain
the generation evidence. Bulky raw outputs and local logs remain ignored.
The independent public-reference audit matched all 64 rows and published metadata
against the actual retained receipts; its zero exit receipt and log are
.work/qualification/20261014/public-reference-independent-audit.{log,exit}.
This reference is intended for future adapter comparisons; no new serving API
or production aggregation policy is introduced.

Final maintained make test passed 144 tests at dc09d44. Maintained make test/probe
also passed: actual network and source/root writes were denied; non-root output
ownership, dropped capabilities, no-new-privileges and resource bounds were
verified. That tooling probe uses two CPU quota units, 512 MiB memory and 64 PIDs;
its memory limit is distinct from the 4 GiB inference container. Exact commands,
revision and zero exit receipts are retained under
.work/qualification/20261014/final-tests.* and final-probe.*.

Slice 001 is complete for this contained, prepared-data, CPUfloat32, fold-0 H/C
reference. Maintained commands perform verified acquisition, offline image build,
preparation and repeated inference. The public reference and retained receipts
make its observed outputs reviewable. Scope remains two intact records per
element; no SMILES preprocessing, provider integration, ensemble qualification,
GPU parity, cross-platform numerical guarantee or paper-level accuracy claim.

Published accuracy and ensemble averaging (checked 2026-10-14)
------------------------------------------------------------

To answer whether the reported accuracy belongs to an ensemble, the exact paper
version was revisited: https://arxiv.org/html/2601.18524v1, Table 2, Section 4.1
and Appendix D. Those passages do not explicitly state five-fold prediction
averaging. The conclusion for Table 2's NMRNet + Semi-supervised rows instead
comes from the released code and matching released result logs. This distinction
avoids attributing an unstated methodological detail to the paper's prose.

Pinned script/infer.sh:11-28 runs five checkpoint folds and invokes the result
helpers in cv mode. get_result.py:80-84 first averages the prediction vectors,
then computes MAE/RMSE; it does not average the five fold metrics:
https://github.com/numpde/fork-of-NMRNetplusplus/blob/3ba8b9c2f3d0a390d00685d238618345c6ab24d7/script/infer.sh#L11-L28
https://github.com/numpde/fork-of-NMRNetplusplus/blob/3ba8b9c2f3d0a390d00685d238618345c6ab24d7/uninmr/utils/get_result.py#L80-L84
The molecule-level helper likewise averages predictions before sorting within
samples and evaluating:
https://github.com/numpde/fork-of-NMRNetplusplus/blob/3ba8b9c2f3d0a390d00685d238618345c6ab24d7/uninmr/utils/get_result_unlabel.py#L97-L103

Six small logs in the already verified checkpoints.zip were read without
extracting models or running inference. The source archive is
https://zenodo.org/api/records/18232165/files/checkpoints.zip/content,
SHA-256 aba477d82049470366dd14088ec0fe03b2e9015c833c98d2dfa191d6aecfee2c.
Member paths are the exact H/C configuration parents declared in
artifacts/checkpoints.selection.json (ending 20250930_033837 and 20251004_182236),
followed by the filenames below. Each log lists five individual fold results
and a final "metric of mean". All six final MAE/RMSE pairs match Table 2:

Element  Member                  MAE     RMSE    Member SHA-256
H        result.log              0.1709  0.4337  73d5785eaa2a96bd66ba577980691aab1f74eec4ba8162c77b40edfb2355ce1c
H        result_unlabel_1.log    0.1492  0.3620  41306587733c33628515761994b8bba80844f520f252d0187fa0171909c4e620
H        result_unlabel_2.log    0.0559  0.1846  1f3210966137557e1c906bad39e49021ad74d592f415f376ef7e24d61df745c7
C        result.log              0.9270  1.9128  84a2533a9530d5f49d2564f6b92775c97c5286214ba2583cb4a3ad15db2a6174
C        result_unlabel_1.log    0.7765  1.5629  00eee3ca11789acf3c0ffd5d796453e14a582c7bf164529d475a60de74a0c8b6
C        result_unlabel_2.log    0.5060  2.3494  d7e334f7e02e9f8459350bb33ec39f9b5800893d31592c4960eac1c7b7afe488

The three filenames correspond respectively to NMRShiftDB2 atom-level,
NMRShiftDB2 molecule-level and ShiftDB-Lit molecule-level evaluation. The H/C
fold-0 atom-level MAEs in those release logs are 0.1842/0.9876, distinct from
0.1709/0.9270 for averaged predictions. This confirms the ensemble basis of
those Table 2 rows; it does not establish the aggregation provenance of every
other method or table in the paper. Our qualified two-record, fold-0 reference
is an execution reference and does not reproduce those ensemble accuracy scores.

Local reproducible evidence is retained in
.work/qualification/20261014/ensemble_claim_probe.{py,sh,log,exit}; exit status
was zero. The pinned offline, read-only, non-root container reads exactly those
six log members, each bounded below 100,000 uncompressed bytes, and prints their
sizes, hashes and contents. No downloads, model loading or inference were needed.

Accidental host-execution guard (2026-10-14)
------------------------------------------

Review found that the contained launchers did not prevent direct host imports or
execution of their Python workers. tools/container_guard.py now owns the shared
require_container() check: only NMRNET_IN_CONTAINER=1 is accepted; rejection
directs the operator to a maintained Make target. This prevents accidental host
execution, while the container engine and launcher grants remain the isolation
authority. A caller-controlled environment marker is not container attestation.

All eleven owned Python workers check this guard before operational imports or
work. Their maintained launchers and build images supply the fixed marker and
the shared module; baseline receipts hash the mounted guard through the existing
tool list. Negative probes simulate missing or invalid markers in fresh contained
subprocesses. No host Python was used for this qualification. The convention suite
also guards its own execution.

make test aggregates test/unit and test/repository: 155 unit tests, 8 repository
checks and the containment probe passed at
6fe70440b99e3d57d9d6e0c66bbcc19025f474d3. The dispatcher evidence is retained in
.work/qualification/guard-qualification-20261014/final-dispatcher-summary.json
and the adjacent final-aggregate.* and final-probe.* receipts.
repository_checks/test_conventions.py
owns recursive guard coverage for tools/, repository_checks/ and the future
nmrnet_inference/ package, plus hierarchical public Make targets and aggregate
wiring. The common guard and empty/docstring-only package markers have narrow,
documented exceptions. Its in-place pinned NMRPeak/Magnet references explain
the suite organization and source-inventory precedent; no separate guard-only
checker command is introduced.

Offline qualification at 2d71ba59642cd4bc26f4c66f7761f92aed26c955 rebuilt the
inference image as
sha256:00c37d0cd9e16a799b35b9e319f9bae27b896bdc3fe57802bf9c82897f7126c4.
Image builds, maintained imports, archive checking, contained tests and posture
probes passed. The lock image accepted its marked import and rejected an invalid
marker. Baseline guardrails-20261014 produced the same 42 H and 22 C predictions in
both repetitions, with zero difference from the original 64-position reference
at unchanged tolerances. Inspection confirmed actual container grants, caller
ownership and container removal; 37 historical evidence files remained unchanged.
Independent review found no remaining issue. The image/model qualification
summary is
.work/qualification/guard-qualification-20261014/qualification-summary.json; its
commands, logs and exit statuses remain alongside it.

The first comparison-audit command used a file-path invocation that could not
resolve the mounted tools namespace before reading data. That failure is retained;
the corrected runpy invocation passed. It was an audit invocation error, not a
failure of the maintained baseline.

This execution-policy change does not rewrite the qualified numerical reference,
its historical image identity, or the original preparation/execution receipts.

Evidence relocation (2026-10-14)
-------------------------------
Completed captures were grouped under .work/qualification/. The paths above
name their current locations; captured commands, scripts, logs and receipts keep
their original bytes and embedded historical paths. Use maintained Make commands
to rerun workflows. The relocation map, before/after hash inventories and
protected-evidence verification are retained in .work/qualification/tidy-20261014/.
The original qualification/20261014 evidence and operational roots stayed in place.

Additional findings from retained acquisition and import logs
------------------------------------------------------------
The retained acquisition-resume.MGfUzdFZ capture started with data.zip.part at
136,314,880 bytes and checkpoints.zip.part at 29,360,128 bytes. Its progress log
records subsequent growth. These are observed partial-file offsets, not proof
of a particular HTTP response or transport cause. Evidence under
.work/qualification/acquisition-resume.MGfUzdFZ/ is resumed-offsets.txt:1-2
(SHA-256 afb7526ff5edff8ab3d8871086b3cf7a2e458ea7a8f684a1068091eaedc1270d)
and progress.log:1-9
(SHA-256 e8a7f7bc19f9fd5a40ea58011966de4cb5f28f0bf5fa0592d295be54a4be06d2).

That data download attempt rejected 402,573,160 bytes against the declared
1,942,805,949 bytes. data.zip.download.log:15-18 records the size rejection
(SHA-256 0931e24cdf4dcf928c04bfc9a8828f5fcfe9023c360870419c4ca3f042a0fabc).
data.worker.exit is 2 and supervisor.exit is 1, while the sibling checkpoint
check/extract exits are both 0. The later setup-20261014/data-retry/state also
records download-failed. Keep these failed attempt outcomes distinct from later
artifact qualification: .work/qualification/20261014/data-check.log:1-2 and
data-check.exit record the full declared size, matching declared MD5, a computed
SHA-256 identity and exit 0 at revision
6ee0fa1f02dc2838b696d8b17cc48523dd583969. The successful log SHA-256 is
0f33b41091264d5bf01f623052ef682c93a2107de100e8cb81033448ada42700.
The failed capture does not establish its worker's exact source/image or why
the transfer ended short; no cause is inferred from its traceback line numbers.

The qualified CPU import smoke printed five missing fused-extension messages,
then reported CPU float32 imports passed, with packages-import.exit equal to 0.
The messages did not establish failure of this CPU lane or qualify GPU/fused
execution. Evidence: .work/qualification/guard-qualification-20261014/
packages-import.log:2-7, SHA-256
057ef2af9b227951033bd8594568a56cf18b00e009f0553ff5b43f1e8c28c099.
Its qualification source is 2d71ba59642cd4bc26f4c66f7761f92aed26c955 and image is
sha256:00c37d0cd9e16a799b35b9e319f9bae27b896bdc3fe57802bf9c82897f7126c4.