Second slice: label-free coordinate prediction

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

Record sections
Second slice: label-free coordinate prediction
Date: 2026-10-14
Status: 002 qualification closed on 2026-10-17 for the retained-fixture atom-coordinate callable; provider integration, SMILES geometry and archive-wide coordinate provenance remain outside this closure
Implementation update: 2026-10-17

Priority correction: 2026-10-17
===============================

Author: repository coordinator. Purpose: align the remaining work with the
maintainer's confirmed goal: a reproducible, contained NMRNet++ provider for
the NMR API. The coordinate callable is an enabling milestone. A standalone
file CLI and a separate prediction-result publication workflow are deferred;
their previous requirements no longer define completion of 002. The prior
design and its review rationale remain in the committed note:
https://github.com/numpde/nmrnet-repro/blob/c8b26e651a0753d0e1e6375240bab25b1e8f4da1/notes/002_label_free_coordinate_prediction_20261014.txt
This is an explicit scope correction, not evidence that an unimplemented gate
has passed. Scientific qualification, containment, resource bounds and useful
safe error propagation remain requirements. Implementation was paused during
that plan/README-only correction and resumed on 2026-10-17; see the construction
update below.

Priorities, in dependency order:

1. Establish the provider-facing input/result/failure boundary from the current
   API and sibling code. Decide what molecular information the offering accepts
   and how it reaches the coordinate callable; record unresolved chemistry
   choices before adding transformations or a new transport. This investigation
   runs alongside model integration so later callers shape the implementation.
2. Connect verified dictionary/checkpoint/scaler bytes to the real registered
   model and head, without task/dataset/loss setup. Exercise real predictions
   on the pinned reference fixtures in the existing contained scientific lane.
3. Qualify numerical overlap, complete atom coverage, reuse, maximum admitted
   workload and safe failures. The repository adopts ångströms for H/C model
   inputs based on the documented evidence and bounded geometry check below;
   retain the evidence limits in the public input contract.
4. Deliver the qualified callable and compact evidence needed by the provider.
   Use the next big slice, 003, for provider integration against the established
   contract, including its container lifecycle and recipient-specific errors.

Source-based rationale for the provider boundary
-----------------------------------------------
Read-only investigation on 2026-10-17 examined magnet-deploy revision
c5813ee35cfbb1c98a5cc5d20a94787271f26486 and nmr-api-v1 revision
6a163b7a9cc1e2c7485b681c0b2b969c7c20e6c8. These are inspected precedents,
not new runtime dependencies or a decision to copy their whole frameworks.

Magnet's ProviderAnalysisProcessor receives verified Job input and returns an
analysis outcome; generic provider code owns Jobs, Attempts and publication.
G01's model worker loads once and serves serial requests over a private socket.
These owners show why an inference callable and its actual provider adapter
belong on the path; a standalone file CLI/publication protocol is not required.
They do not prescribe a socket worker for NMRNet or qualify NMRNet's science:
https://github.com/numpde/magnet-deploy/blob/c5813ee35cfbb1c98a5cc5d20a94787271f26486/magnet_provider/analysis_contract.py#L158-L207
https://github.com/numpde/magnet-deploy/blob/c5813ee35cfbb1c98a5cc5d20a94787271f26486/models/g_01_nmr_forward/provider/magnet_provider_bindings/g_01_nmr_forward/binding.py#L1-L5
https://github.com/numpde/magnet-deploy/blob/c5813ee35cfbb1c98a5cc5d20a94787271f26486/models/g_01_nmr_forward/runner/serving_worker.py#L58-L148

The API admits user-authored Job specification text; it does not require a
SMILES or coordinate model-input schema. G01's interpreter extracts explicit
SMILES/solvent without inventing chemistry. Therefore the NMRNet offering still
needs a deliberate input adaptation decision: coordinates need exact extraction,
units and atom correspondence; SMILES additionally needs qualified geometry
generation. An interpreter is an adapter choice, not an API requirement.
The API's existing outcome path accepts a result schema identity and encoded
result bytes, so the provider should own publication through that contract:
https://github.com/numpde/nmr-api-v1/blob/6a163b7a9cc1e2c7485b681c0b2b969c7c20e6c8/nmr_api/public/job_create_request.py
https://github.com/numpde/magnet-deploy/blob/c5813ee35cfbb1c98a5cc5d20a94787271f26486/models/g_01_nmr_forward/provider/magnet_provider_bindings/g_01_nmr_forward/prompts/interpreter.md
https://github.com/numpde/nmr-api-v1/blob/6a163b7a9cc1e2c7485b681c0b2b969c7c20e6c8/nmr_api/provider/execution_attempt_outcome.py#L168

The provider boundary must also preserve execution uncertainty and route safe
causes to each recipient. G01 distinguishes model replies lost after transmission
from interpreter unavailability before transmission, and its failure policy
controls which classified diagnostics reach API clients. These are applicable
ownership/error lessons; their exact classifications are not automatically the
NMRNet offering's policy:
https://github.com/numpde/magnet-deploy/blob/c5813ee35cfbb1c98a5cc5d20a94787271f26486/models/g_01_nmr_forward/provider/magnet_provider_bindings/g_01_nmr_forward/processor.py#L170
https://github.com/numpde/magnet-deploy/blob/c5813ee35cfbb1c98a5cc5d20a94787271f26486/models/g_01_nmr_forward/provider/magnet_provider_bindings/g_01_nmr_forward/analysis_failure_policy.py

Current implementation evidence
===============================

Real-model construction update (2026-10-17)
------------------------------------------
The coordinator implemented the direct registered-model constructor in
nmrnet_inference/model.py::load_prediction_model_from_bytes. The shared
MODEL_SETTINGS also feeds the baseline; encoder defaults remain owned by the
pinned upstream architecture. The dictionary loader appends MASK as upstream
does. Full state loads strictly, CPUfloat32 parameters/buffers are checked, and
eval mode is established without a training Task, dataset or loss.

The maintained contained make prediction/model-parity lane now loads both exact
001 checkpoints and paired scalers from verified immutable member snapshots.
It matches all 64 historical positions at ATOL=RTOL=0, independently checks all
H/C atom indices across all four fixtures, repeats them in reversed order, and
exercises synthetic 1/128-atom and absent-head cases. Synthetic geometry proves
capacity only. Constructed model args match a fresh-process resolution of the
upstream baseline invocation. Each model has 47,593,795 parameters. Observed
cgroup grants are two CPUs, 4 GiB memory, zero swap and 64 PIDs; peak memory was
2,194,231,296 bytes. This is local retained-fixture/capacity evidence, not unit
qualification, broad chemical accuracy or a completed provider interface.

Focused results: model-contract 9, launcher 17, request 26, tensor parity 23;
the real-model integration test passes in 10.937 seconds. Evidence is retained
under .work/qualification/002-real-model-20261017/. The initial baseline-launcher.log
failed its source-list expectation; the initial model-parity.log stopped at
Uni-Core's duplicate-plugin guard before numerical comparison. Their .v2.log
reruns pass after test-only corrections; no tolerance was changed. Released
scalers emit their saved sklearn 1.5.2 versus runtime 1.8.0 warning; it remains
in the logs and the unchanged fixture computation matches exactly. The final
portable observation packet and failure/lifecycle proof were pending at this
construction milestone; subsequent updates below close their fixture-scoped
requirements and composed loading. Unit closure remains open. Test-only unit
labels leave both production unit gates unset.

Selected-artifact request update (2026-10-17)
--------------------------------------------
nmrnet_inference/release.py::SelectedReleaseModels supplies the existing
predict_request callbacks. Construction captures paths without I/O; admission
still precedes dictionary reads and vocabulary checks precede checkpoint/scaler
work. Each head's two immutable snapshots are verified before either is decoded.
No model is retained on the loader, so the request owner releases H before C.

artifacts/prediction-models.json is the normative runnable selection: dictionary
and H/C fold-0 checkpoint/scaler member sizes, hashes and archive identities.
Its reviewed initial values come from artifacts/reference-cpu-float32.json
(the packet hash is recorded below). This is an intentional distinction of
roles: the new declaration specifies what may run; the immutable 001 packet
records what was observed. Production does not read historical predictions,
fixtures or training logs. The scientific lane independently compares all five
members and archive identities to 001 and checks the extraction allowlists.
Extraction receipts alone cannot pin qualified bytes: changing both a member
and its receipt could otherwise admit different objects. The loader requires
agreement with the trusted declaration as well as the receipt before decoding
the same bytes. Its declaration is capped at 64 KiB; extraction receipts now
use the existing regular-file/no-follow boundary with an actual 1 MiB + 1
read cap (commit 12ffa34; 30 focused preparation tests passed in 0.017 s).

The maintained prediction/model-parity lane mounts the new declaration read-only
and executes JSON bytes through predict_request and these actual callbacks,
using only test-injected unit labels. All four fixtures and their reversed
repetition return complete sorted H/C atom coverage and exact historical overlap.
The unchanged direct-constructor/configuration/capacity checks also pass.
Three scientific integration tests pass in 33.993 s; the final observed memory
peak is 1,891,094,528 bytes within the unchanged 4 GiB/no-swap grant.
Focused request/selection tests pass 32 cases, including forged member receipts,
paired-scaler rejection before checkpoint decoding, no I/O for rejected requests,
archive mismatch, metadata bounds and decoder-cause propagation. Launcher tests
pass 17 cases. Logs under .work/qualification/002-real-model-20261017/ are
prediction-selection.log, baseline-launcher-selection.log and
composed-model-parity.log. This is retained-fixture wiring evidence; physical
unit qualification and provider integration remain open.

Failure, lifecycle and portable fixture evidence (2026-10-17)
------------------------------------------------------------
The real composed failure test completes H inference, injects a C selected-loader
failure with a nested private-request sentinel, and checks that the identical
exception and cause reach the authorized caller and no result returns. The
sentinel is carried in the test-only unit label as well as the injected cause;
the model's numerical coordinates are unchanged. Captured stdout/stderr contain
neither the sentinel nor the raw request. This is real-H/injected-C failure
evidence, not a C decoder fault, sanitized traceback or permission to disclose
arbitrary upstream causes to a future public recipient.
Existing admission tests keep molecular values out of parser diagnostics and
decoder context; the provider's eventual recipient projections belong to 003.

baseline.sh now uses --init, following tools/container.sh's maintained test lane
(revision 40b8f81, lines 262-266). The inspected SECS precedent uses the same
grant for contained work:
https://github.com/numpde/secs-repro/blob/34f5915c1534278bbf61b4c6592afa44cf94ab08/Makefile#L180
The rationale is signal delivery/reaping: Python must run as an ordinary child,
rather than relying on PID 1's default signal behavior. Docker documents init,
default signal proxying and exact-container CID-file instrumentation here:
https://docs.docker.com/reference/cli/docker/container/run/
Those mechanisms motivate the change; they are not themselves runtime proof.

A one-off host-orchestration probe exercised the maintained model-parity lane.
Its private Docker delegator added only --cidfile, preserving the launcher's
scrubbed endpoint and other arguments. It waited for the scientific test start
and inspected that exact ID as running with init enabled, then sent TERM only
to its captured launcher child. The launcher returned 143. A successful exact-ID
engine listing then confirmed absence, without container cleanup intervention.
This qualifies TERM cancellation for this supported workload/engine, not arbitrary
TERM-resistant workloads or every future launcher. Local process retirement
alone still does not establish engine-side retirement. Ignored probe source and
raw evidence are retained in .work/qualification/002-real-model-20261017/:
probe-cancellation.sh, cancellation-launcher.v2.log, cancellation-probe.v2.log.
The first probe failed in its controller's /proc disappearance race; its original
cancellation-probe.log and cancellation-launcher.log remain. That was a probe
failure, not evidence of successful or failed engine cancellation. No broad
container matching, stop, prune or cleanup was used.

The public artifacts/prediction-fixture-cpu-float32.json records the composed
fixture observation: original atom lists, all 137 eligible H/C predictions,
64 exact historical overlaps, request hashes, effective model identities,
original verified reference/receipt identities, runtime and cgroup facts.
Source hashes and configuration files reopened after execution are explicitly
observations at that time; caller-reported parent HEAD does not identify dirty
source bytes. Public fixture coordinates are not copied into the packet.
The scientific lane emits this observation only after composed assertions and
flushes it before unittest resumes stderr reporting. Public retention requires
the entire container command to exit zero and the record to parse as JSON; an
emitted record alone never establishes whole-lane success. It is a historical
observation, not a deterministic generated-current-state file (013 U06/U19/U20).
Rerunning make prediction/model-parity produces a new observation; resource
peaks may differ. This packet is not final external-input qualification.

The initial four-test runs passed, but one stdout/stderr-interleaved record could
not be cleanly extracted. fixture-observation-init.log preserves that run; no
failed extraction was accepted. Single-record writing and flushing correct the
test harness without changing model computation or numerical tolerance.

The final recorded lane, fixture-observation-final.log, passes all four tests in
35.521 s. The packet includes atoms in original order so an independent reader
can derive every eligible index and element without decoding LMDB. Its memory
sample is 1,781,399,552 bytes immediately after composed fixture/reuse execution;
the later direct-model sample reaches 1,831,641,088 bytes. Both are within the
4 GiB/no-swap grant. The packet is 27,074 bytes, SHA-256
8027e0329bde7608d8e80bb5e64e94bdcdd4add2941b1c86c1bb9680bef22496.
The focused launcher rerun passes 17 tests (baseline-launcher-init.log).
Independent Use/Avoid/code reviews challenge code, identity scopes, exact
populations, privacy and actual evidence before the path-limited commit.

The bounded, dependency-light request reader and structural parser are now in
`nmrnet_inference/predict.py`, with focused coverage in
`tests/test_prediction_input.py`. The reader hashes the exact bounded bytes it
returns for parsing. All 26 focused tests pass via the maintained
`test/unit/prediction-input` Make target, which runs only this module in the pinned
`docker.io/library/python:3.12.12-slim-bookworm@sha256:593bd06efe90efa80dc4eee3948be7c0fde4134606dd40d8dd8dbcade98e669c` image with
read-only source mounts and network disabled. The parser requires a nonempty
caller `coordinate_unit` string and preserves it; it does not establish physical
unit compatibility. At this implementation milestone, code kept
`QUALIFIED_MODEL_COORDINATE_UNITS` unset for H and C independently pending
evidence. The later decision below records the adopted convention. The
`predict.parse_request` checks the exact unit for every H/C model required by
the structurally valid request before returning it, so an unqualified or
mismatched head blocks downstream artifact work. Context atoms do not select a
head; a C or H atom beside any context atoms still requires its matching head.
The public
`model.compose_net_input` repeats the check before tensor composition. Parity
tests inject a test-only matching label for only the element under test; that
does not qualify either real model unit.
The label-free `predict_element` forward, real model constructor and
`predict_request` orchestration exist. Production selected-artifact callbacks
now connect to the request orchestrator; unresolved unit values still block
external H/C requests. Synthetic forward tests and the real-model
fixture lane have distinct scope; neither authorizes external input units.
At the time of this implementation update, external coordinate requests were
blocked by unset gates. The 2026-10-17 ångström decision below supersedes that
status; the exact retained-fixture dictionary remains bound to the 001 packet.

Malformed JSON reports the parser's safe reason and line/column; invalid UTF-8
reports the failing byte position. The decoder exceptions are not retained as
causes because they hold the full request. Focused sentinel tests verify that
neither exception context nor a formatted traceback exposes the request value.
Input read failures remain operational `OSError` or `BlockingIOError` outcomes.
This is a diagnostic-disclosure check, not a memory-erasure guarantee: Python
traceback frames can retain caller-owned locals while an exception is alive.

Label-free tensor composition
-----------------------------

`nmrnet_inference/model.py` composes the five CPU tensors for one admitted
ordered atom list and one H or C head. It uses only atom tokens, the element
selection mask, centered coordinates, pairwise distances, edge types, and
right-padding. Requests above 128 atoms are rejected before scientific imports
or pairwise allocation; the adapter does not apply the training dataset's
random crop. Exact dictionary identity/order and coordinate-unit qualification
remain separate gates. The same real-atom selection produces the `select_atom`
tensor and `selected_atom_indices`, a tuple of zero-based input positions in
model-row order. BOS, EOS and padding are excluded, and the mapping stays outside
the five model keyword arguments.

The operation order follows the pinned sources. `CroppingDataset` casts selected
coordinates to float32 (`NMRNetplusplus/uninmr/data/cropping_dataset.py:27-38`),
then `NormalizeDataset` subtracts their per-axis mean and retains float32
(`NMRNetplusplus/uninmr/data/normalize_dataset.py:20-26`). `UniNMRTask` orders
cropping before normalization, creates tokens and element masks, computes
Euclidean distances, adds BOS/EOS borders, and builds edge types
(`NMRNetplusplus/uninmr/tasks/uninmr.py:348-379`). `DistanceDataset` uses the
SciPy p=2 distance matrix and casts it to float32
(`NMRNetplusplus/uninmr/data/distance_dataset.py:13-24`). The task's right-pad
collaters pad each tensor axis to a multiple of eight
(`NMRNetplusplus/uninmr/data/pad_dataset.py:13-47,49-66,88-102`).

The coordinate boundary markers are scalar `0.0` arguments in the upstream
task. Uni-Core's pinned `PrependTokenDataset` and `AppendTokenDataset` create
each marker with `torch.full_like(item[0], token)`, so a scalar marker has the
same three-value row shape as the coordinates
(`https://github.com/dptech-corp/Uni-Core/blob/ace6fae1c8479a9751f2bb1e1d6e4047427bc134/unicore/data/prepend_token_dataset.py#L14-L25`,
`https://github.com/dptech-corp/Uni-Core/blob/ace6fae1c8479a9751f2bb1e1d6e4047427bc134/unicore/data/append_token_dataset.py#L14-L24`). The source pin and archive hash are recorded in
`requirements/unicore-source.json`: commit
`ace6fae1c8479a9751f2bb1e1d6e4047427bc134`, archive SHA-256
`ae240ff27dfc4c698081260d58ce4bee30d4f437fef23bed89d4033625f21583`.
`tests/test_prediction_model.py` uses these
actual wrappers as its oracle and checks exact tensor dtype, shape, and values
for H and C at one and 128 atoms. Its 128-atom fixture uses fractional
coordinates to exercise the float32-before-centering order. It also checks
CPU placement, zero BOS/EOS borders, eight-wide padding, malformed coordinates,
the pre-import and pre-distance 128-atom bound, oversized integers, and
non-echoing unsupported-atom errors. It verifies that selected input indices
match the real rows of the mask for repeated mixed H/C atoms, and that absent
elements have no selected indices or real mask rows. Unsupported-atom errors
report an atom index rather than repeating caller input, retaining an actionable
location without echoing the request payload.

An earlier focused module run passed seven synthetic tensor tests in the
locally recorded inference image
`sha256:cabb4fe3e36541b0fefe54ca7c16fb21f9a60112a1e3d47992d4aa18343ecd08`
with:

```text
python3 -B -m unittest discover -s /workspace/tests -p test_prediction_model.py -v
```

The run used a read-only source mount and container root filesystem, no network,
UID/GID 65532, no Linux capabilities, no-new-privileges, two CPUs, 2 GiB memory
and swap, 64 processes, and a 64 MiB noexec/nosuid `/tmp`. This was a focused
contained test run, not a maintained prediction-parity target. It established
synthetic tensor parity only; no retained 001 record, coordinate-unit meaning,
checkpoint/scaler loading, model call, or chemical-shift prediction was tested.
The tested implementation was the 2026-10-17 working tree based on repository
commit `37fa36bd92e8cc431d173f76b6b96ebebf79353e`; the model and test changes
were uncommitted during that earlier run.

Retained-record tensor parity now runs as `make prediction/tensor-parity`. The
target uses the recorded inference image
`sha256:cabb4fe3e36541b0fefe54ca7c16fb21f9a60112a1e3d47992d4aa18343ecd08`,
whose upstream label must match submodule revision
`3ba8b9c2f3d0a390d00685d238618345c6ab24d7`; it also checks that the image's
embedded `inference.lock` and `unicore-source.json` match the read-only checkout
inputs. The oracle and production adapter are compared for both H and C on all
four 001 records. `src_tokens`, `src_coord`, `src_distance`, and `src_edge_type`
match exactly in dtype, shape and values. The upstream oracle receives each
record's real `atoms_target_mask`; production receives only atoms, coordinates,
dictionary and head, and its all-real-atom output mask is checked separately.

The test admits the exact prepared receipt bound into the tracked 001 packet:
`artifacts/reference-cpu-float32.json` has SHA-256
`8268206ad12003dea5ef57e1a7392de69325e110b54f2b91ee0f6314c4fef5ae`, and its
recorded prepared-receipt identity is SHA-256
`b866ea1a659a699cdab5cce5f3b829dc58aa28a0a60d6e1173164554e08f7e81` (7,499
bytes), equal to the receipt read from `.work/baseline/prepared/provenance.json`.
The four record keys, raw-record hashes, atom counts, selected indices and
ordered dictionary are checked against that packet before tensor comparison.
Only identity fields are used from the packet; labels and predictions are not
passed to the adapter.

The retained LMDB records are Python pickles, so the parity container resolves
only the NumPy reconstruction globals required by these pinned records. A
focused test rejects an unapproved Python global, pickle extension opcodes and
persistent IDs before resolution. Fixture files are bounded, hash-checked
against the exact receipt, and decoded only in the offline, resource-limited
container. The tracked 001 packet anchors the local receipt; local hashes alone
are not treated as authentication. The lane grants no checkpoint, model-output
or writable host path.

The maintained target passed all 13 tests in the recorded inference image. The
focused launcher regression passed all 16 tests in the pinned unit image, using
read-only source mounts, no network, a read-only root, UID/GID ownership, no
capabilities, no-new-privileges and bounded CPU, memory, processes and `/tmp`.
The parity launcher consumes the retained 001 preparation and does not require
the original extracted archives to remain present.
This closes retained-fixture tensor parity only. It does not establish the
released coordinates' external unit, model/scaler loading, model execution,
predicted shifts or chemical accuracy; the coordinate-unit gate and prediction
qualification remain open.

Verified model-artifact byte boundary (2026-10-17)
--------------------------------------------------

`tools/baseline_prepare.py::verified_member_bytes` now reads one selected
extracted member through its already-open regular-file descriptor, rejects an
initial size above that selection's `max_bytes`, caps consumption at
`max_bytes + 1`, and compares the consumed bytes' size and SHA-256 with the
extraction receipt before returning the immutable byte snapshot and its
identity. The receipt identifies the locally extracted member; it is not an
independent authentication of the upstream release. The existing path-returning
`verified_member` still serves preparation callers.

`nmrnet_inference/model.py` adds byte-only decoder helpers for the pinned
Uni-Core checkpoint (`torch.load` on a byte stream, mapped to CPU with
`weights_only=False`), the paired scaler (`joblib.load` on a byte stream), and
the ordered dictionary (`Dictionary.load` on a UTF-8 text stream). Their decoder
behavior follows the exact pinned sources:

- Uni-Core `load_checkpoint_to_cpu`:
  https://github.com/dptech-corp/Uni-Core/blob/ace6fae1c8479a9751f2bb1e1d6e4047427bc134/unicore/checkpoint_utils.py#L244-L251
- NMRNet++ `TargetScaler`:
  https://github.com/numpde/fork-of-NMRNetplusplus/blob/3ba8b9c2f3d0a390d00685d238618345c6ab24d7/uninmr/utils/data_scaler.py#L32-L38
- Uni-Core `Dictionary.load`:
  https://github.com/dptech-corp/Uni-Core/blob/ace6fae1c8479a9751f2bb1e1d6e4047427bc134/unicore/data/dictionary.py#L93-L108

`tests/test_prediction_model.py` verifies receipt size and digest mismatches,
initial oversize rejection before reading, bounded detection of growth during
reading, and that decoder inputs remain the verified snapshots after the source
path is overwritten or replaced. The decoders reject path objects. An earlier
run of the maintained `make prediction/tensor-parity` target passed all 18 tests
in the recorded inference image with the existing no-network, read-only source policy.
These tests use synthetic checkpoint, scaler and dictionary values: they do not
deserialize the released checkpoint or scaler, construct either element model,
or establish model compatibility, prediction parity or scientific accuracy.
Checkpoint/scaler/dictionary admission and prediction qualification remain
open.

Label-free forward and request orchestration (2026-10-17)
---------------------------------------------------------

`nmrnet_inference.model.predict_element` composes one H or C input, calls the
selected upstream head in evaluation mode with gradients disabled, and requires
one CPU float32 scalar per selected atom. It applies that head's paired scaler
inverse exactly once, checks the returned shape and finiteness, then pairs each
ppm value with the original input atom index from the same mask traversal.
Selection is already performed by the pinned UniMat node-head branch:
`UniNMRTask` defaults to `nmr_head` and registers it as a node-classification
head, and UniMat gathers `model_input[select_atom==1]` before applying that
head. With the task's `num_classes=1`, its result is one scalar row per selected
atom. The loss's later reshape does not perform this selection, so the adapter
validates and preserves the model's selected-row output without masking twice.
The invocation, head registration and output shape follow these exact sources;
inverse scaling follows the loss path:

- https://github.com/numpde/fork-of-NMRNetplusplus/blob/3ba8b9c2f3d0a390d00685d238618345c6ab24d7/uninmr/tasks/uninmr.py#L71-L79
- https://github.com/numpde/fork-of-NMRNetplusplus/blob/3ba8b9c2f3d0a390d00685d238618345c6ab24d7/uninmr/tasks/uninmr.py#L462-L469
- https://github.com/numpde/fork-of-NMRNetplusplus/blob/3ba8b9c2f3d0a390d00685d238618345c6ab24d7/uninmr/models/unimat.py#L276-L280
- https://github.com/numpde/fork-of-NMRNetplusplus/blob/3ba8b9c2f3d0a390d00685d238618345c6ab24d7/uninmr/models/unimat.py#L405-L422
- https://github.com/numpde/fork-of-NMRNetplusplus/blob/3ba8b9c2f3d0a390d00685d238618345c6ab24d7/uninmr/losses/atom_regloss.py#L32-L35
- https://github.com/numpde/fork-of-NMRNetplusplus/blob/3ba8b9c2f3d0a390d00685d238618345c6ab24d7/uninmr/losses/atom_regloss.py#L75-L76

`predict_request` parses and admits every present head's coordinate-unit gate,
then loads the selected ordered dictionary and rejects any atom without a
dedicated token before invoking a model loader. Each model callback receives
that same dictionary and returns only its selected model and paired scaler.
This makes vocabulary rejection precede checkpoint/scaler deserialization at
the orchestration boundary. It then loads and predicts H followed by C,
skipping absent heads, and returns one atom-index-sorted ppm result only after
every required head succeeds. A later head exception propagates and no partial
result is returned. Production artifact selection and composed retained-fixture
execution now pass in the lane described above. External units and final
external-input evidence remain open.

The focused regressions prove unit-gate-before-loader ordering, absent-head
skipping, sequential H/C calls and index merging, all-or-nothing return behavior,
named-head evaluation, one inverse-scaler call, output shape/dtype and finite
value checks. `make prediction/tensor-parity` passed all 23 focused model tests
in the recorded inference image, and `make test/unit/prediction-input` passed
all 26 request-admission and orchestration tests in the pinned unit image. The
unknown-vocabulary regression uses a test dictionary that maps Xe to its UNK
index and proves the model-loader callback is not called; it does not exercise
the released dictionary or a release loader. Malformed JSON and unqualified
model units fail before dictionary loading.
These runs used the maintained contained targets. They test synthetic
model/scaler behavior and retained-record tensor parity; they do not load the
release checkpoint or scaler, establish coordinate units, compare predicted
shifts with the 001 reference, or qualify chemical accuracy. H/C remain blocked
by the unset release-unit gate.

Purpose and completion boundary
===============================

Implement reusable direct H/C chemical-shift prediction from an explicit ordered
atom list and matching coordinates, ready for a provider adapter. The composed
callable must predict every H/C atom supplied, preserve original atom indices,
and qualify its computation
against the CPUfloat32 fold-0 reference established in note 001. Training labels,
label masks, LMDB records and loss evaluation must not enter the production
prediction interface. The existing model already accepts label-free tensors;
this slice removes the surrounding benchmark-data dependency.

Keep the same image/dependencies, dictionary, paired scalers and fold-0 checkpoints;
no new downloads/installations are expected. artifacts/reference-cpu-float32.json
and its original receipts remain historical evidence, not runtime configuration.

Inspect the provider contract and record its input adaptation decisions now;
implementation of provider transport belongs to the next big slice, 003.
SMILES parsing, hydrogen addition and conformer generation require a justified
scientific/input policy before implementation. Defer a standalone prediction
CLI, its result-directory protocol, solvent-aware variants, five-fold ensembles,
larger tensor batches, GPU/reduced precision and persistent workers. Published
Table 2 ensemble accuracy is not a claim of this slice.

Owners and precedents
=====================

Follow existing small inference owners, not their surrounding service frameworks:

- G01: load the checkpoint and resources that interpret its heads together;
  accept one molecule per call and keep atom identities explicit in the result.
  Its projected SMILES atom order
  is specific to G01; this adapter instead preserves the supplied atom order.
  https://github.com/numpde/magnet-deploy/blob/2d4ee50b0359e71900fce9289ea01f46d0f41249/models/g_01_nmr_forward/magnet/stairway/g_01_nmr_forward/predict.py#L80-L249
  https://github.com/numpde/magnet-deploy/blob/2d4ee50b0359e71900fce9289ea01f46d0f41249/models/g_01_nmr_forward/magnet/stairway/g_01_nmr_forward/predict.py#L43-L67
- SECS: one loaded inference object owns the admitted model, precision and input
  transformations; model construction and evaluation are separate from provider
  transport. Reuse this ownership pattern, not its spectrum/SMILES semantics.
  https://github.com/numpde/secs-repro/blob/34f5915c1534278bbf61b4c6592afa44cf94ab08/src/secs_inference/model.py#L28-L185
- NMRPeak: validate actual input against the loaded dictionary before model
  execution; preserve an explicit boundary around the loaded stack.
  https://github.com/numpde/nmrpeak-repro/blob/f8055ab1065795fd46f8c1539e894cf9773f5495/families/nmrpeak/runner_runtime.py#L43-L170
- Container grants: G01's read-only runtime and explicit resource/input grants
  are precedent; adapt the present repository's offline one-shot launchers rather
  than copying its service topology.
  https://github.com/numpde/magnet-deploy/blob/2d4ee50b0359e71900fce9289ea01f46d0f41249/models/g_01_nmr_forward/runner/serve.compose.yml#L6-L29

Local authorities to reuse: artifacts/*.selection.json plus verified extraction
receipts identify model members; tools/artifacts.py owns archive-member checks and
the staged-directory publication used by artifact extraction, not prediction
receipts; tools/baseline_prepare.py owns file identity and mounted execution
provenance; tools/baseline_model.py owns existing model/dictionary/load
qualification checks; tools/baseline.sh and tools/inference_image.sh own current
image admission and container conventions. Share only functions genuinely needed
by both callers. Do not make prediction call baseline preflight just to manufacture
a training task or copy its full task/loss path.

Execution provenance now uses exact repository-relative source names paired
with the paths mounted by the launcher. One action-specific source list drives
both mounts and `--tool-source` arguments; `execution_identity` remains the
single owner of duplicate-name rejection. Receipt keys therefore distinguish
same-basename files in different directories, while existing baseline tool
names and historical receipts remain unchanged. Focused contained coverage
passed: 28 preparation tests, 11 baseline-run tests, and 16 launcher tests.
The exact maintained commands are `make test/unit/baseline-prepare`,
`make test/unit/baseline-run`, and `make test/unit/baseline-launcher`; each runs
only its named module in the pinned unit image. The run target was added at:
https://github.com/numpde/nmrnet-repro/blob/1fbcb3408977721e90ec3dfa73c3f75fc2740973/Makefile#L71-L78
The source-pair behavior is implemented in:
https://github.com/numpde/nmrnet-repro/blob/54e3bc3e4a3151cdf4ee1cd084db77bd4e4bf986/tools/baseline_prepare.py#L145-L173
https://github.com/numpde/nmrnet-repro/blob/54e3bc3e4a3151cdf4ee1cd084db77bd4e4bf986/tools/baseline.sh#L102-L147
https://github.com/numpde/nmrnet-repro/blob/54e3bc3e4a3151cdf4ee1cd084db77bd4e4bf986/tools/baseline.sh#L269-L273
Tests cover equal basenames, duplicate names and exact source-to-mount pairs:
https://github.com/numpde/nmrnet-repro/blob/54e3bc3e4a3151cdf4ee1cd084db77bd4e4bf986/tests/test_baseline_prepare.py#L40-L89
https://github.com/numpde/nmrnet-repro/blob/54e3bc3e4a3151cdf4ee1cd084db77bd4e4bf986/tests/test_baseline_launcher.py#L123-L139

Proposed minimal file ownership
===============================

- nmrnet_inference/model.py: the loaded scientific boundary and exact label-free
  tensor preparation, using upstream classes/helpers wherever available.
- nmrnet_inference/predict.py: bounded single-molecule JSON input, atom ordering
  and all-or-nothing H/C callable composition. Provider publication belongs to
  the later provider integration, with no parallel result protocol in 002.
- Reuse the contained scientific lane for real-model qualification. Extend its
  launcher only where the callable's actual inputs/grants require it; no host
  Python or separate product CLI is needed to complete 002.
- tests/test_prediction_input.py: lightweight offline admission/orchestration tests
  in the ordinary maintained test image; do not add Torch to that image. A fresh
  contained process must import the lightweight admission path with Torch and
  Uni-Core unavailable, and reject malformed JSON, field, shape, count and raw
  number inputs. Test that all input admission completes before checkpoint/scaler
  deserialization, model construction or forward execution. Dictionary-dependent
  vocabulary checks use the admitted dictionary before checkpoint loading. Keep
  heavy imports behind the lightweight checks; do not add an import framework.
  This applies 013 U11's dependency-boundary and forbidden-effects guidance; see
  its cited source and rationale at
  https://github.com/numpde/nmrnet-repro/blob/e6a8a1b1a2dd5cb854d70277f40d3275945ce933/notes/013_sibling_practices_20261016.txt#L151-L160.
- tools/prediction_parity.py plus a maintained qualification target: scientific
  tensor/checkpoint/prediction proof in the admitted inference image, against the
  verified original records and the 001 reference. Test data and original labels
  stay here, outside the prediction interface.

Consolidate filenames if fewer natural owners suffice. No generic adapter framework,
registry, configurable backend factory or mirrored model architecture is needed.

No fork change is currently justified. If an upstream helper needs extraction,
propose the smallest fork change, prove equivalence and update the submodule;
do not patch image-owned scientific source silently.

Callable input/result contract
===============================

The existing bounded JSON reader is the coordinate callable's admission
boundary, not an NMR API Job schema or a promise of a file CLI. Qualification
passes one molecule's exact bytes with coordinate_unit, atoms and coordinates.
The provider will need a reviewed mapping from its admitted Job input to this
boundary; this plan does not prescribe how user-authored text becomes molecular
input. Checkpoints, device, precision, masks and model settings remain fixed.
For example:

  {"coordinate_unit":"angstrom","atoms":["C","H"],
   "coordinates":[[0.0,0.0,0.0],[1.09,0.0,0.0]]}

Every request must include `coordinate_unit`. Parsing preserves its exact spelling
and does not default, normalize, rescale coordinates or infer physical meaning.
Before returning, it compares that exact label with the evidence-qualified unit
for each present H/C prediction head; other atoms remain context and do not
select a head. Until a needed model unit is qualified, parsing rejects the
request before model or artifact work. After qualification, only an exact label
match is admitted. Every prediction entrypoint must call this parser before
artifact access and retain the composer's second check before tensor creation.
This keeps the possible training unit open without guessing.

This example illustrates shape only, not a qualified molecule. Caller atom
inventory and order are authoritative: no addition/removal/reordering,
canonicalization, coordinate generation or repairs. These fields do not
establish bond/valence validity.

Proposed admission bounds: at most 1 MiB input bytes, 1-128 atoms and one 3-vector
per atom. These are local resource choices, not learned model chemistry limits.
Read at most the byte limit plus one, then hash and parse the same bounded buffer;
never hash the input path separately and reopen it for parsing. A read-only mount
does not prevent a host rewrite: provenance must identify exactly the bytes used.
In contained scratch, test both an initially oversized source and one that grows
past the limit during reading, with appended bytes available before the reader
reaches EOF. Prove total consumption stays within the byte limit plus one and
oversized input is rejected before parsing. Inject a read failure and keep it an
operational error rather than classifying it as malformed user input. This applies
013 U13's consumed-work and operational-failure guidance; see its cited source
and rationale at
https://github.com/numpde/nmrnet-repro/blob/e6a8a1b1a2dd5cb854d70277f40d3275945ce933/notes/013_sibling_practices_20261016.txt#L176-L184.
Check atom counts and row dimensions before array conversion or quadratic
allocation. Reject extra fields (including
labels or selection-mask overrides), duplicate JSON object keys, unknown atom
symbols and model special tokens. Atom symbols must have dedicated ordinary
chemical-element entries in the loaded dictionary; mapping to UNK is not allowed.
Reject booleans used as numeric coordinates and nonfinite numbers. Check finite
values both before and after float32 conversion: finite JSON/float64 values can
overflow float32. Centering and distance construction must also produce finite
tensors before model execution.

Output has unit="ppm" and predictions ordered by original zero-based atom_index,
each with atom_index, element and shift_ppm. Every H/C
atom appears once; other atoms remain molecular context. Absent nuclei yield no
entries; neither H nor C yields an empty list without an empty-tensor model call.
Hydrogen completeness belongs to the caller. Qualification evidence carries
artifact identities and resource facts; per-prediction entries keep atom identity
and shifts. Provider result/provenance projection belongs to its later adapter.

Coordinate-unit evidence gate
=============================

Bounded primary-source search (2026-10-17): the release v1 metadata and Files
at https://zenodo.org/records/18232165 (18 January 2026) were checked for the
selected release's input convention; no checkpoint-specific unit statement was
found. The official https://github.com/YongqiJin/NMRNetplusplus#readme,
Datasets & Models and Running, was checked for a newer inference contract;
it links the release/scripts but states no applicable coordinate unit. This
moving-main observation has no recorded commit ID and is discovery evidence
only, not pinned checkpoint provenance. Issue 1,
https://github.com/YongqiJin/NMRNetplusplus/issues/1 (opened 1 July 2026;
Description/Activity viewed 17 October 2026), was checked for release
clarifications; its missing-checkpoint/split discussion supplies no applicable
unit statement or displayed maintainer clarification. The paper,
https://arxiv.org/html/2601.18524v1, sections 3.1, 3.3, 4.1 and appendices A/C/D,
was checked for preprocessing/model-input scale; no explicit inference unit
tied to the selected checkpoint bytes was found. These bounded negative
findings do not establish that no other evidence exists. No author contact,
new downloads or scientific execution occurred in this search.

**Decision, 2026-10-17: use ångströms for H/C coordinate inputs.** The
repository records this as its operational input contract, enforced by
`nmrnet_inference.predict.QUALIFIED_MODEL_COORDINATE_UNITS = {"H": "angstrom",
"C": "angstrom"}`. Requests must state exactly `angstrom`; no conversion is
performed. This decision uses three pieces of evidence: the pinned upstream
preprocessing path generates RDKit conformers, whose documented bond-distance
convention is ångströms; the model dataset wrapper centers coordinates without
rescaling; and `tests/test_bond_distances.py` compares two exact retained
validation records with NIST gas-phase structural values. The test finds C–H
distances near the references and C–Cl distances near the references at the
declared tolerances.

The empirical check covers only CH3Cl and CH2Cl2 from one validation LMDB, and
uses a broad 0.04 Å C–Cl tolerance because the released records have C–Cl
distances near 1.803 Å (the two experimental references are 1.785 and 1.767 Å).
It supports an ångström-scale interpretation and catches gross scale errors;
it does not prove every archived coordinate record or the exact historical
training input producer used ångströms. The archive-to-training-input producer
link remains unknown as documented below. This is an explicit operational
choice under bounded evidence, not a claim of universal provenance or full
scientific qualification. If later source evidence contradicts this convention,
revise the contract and qualification record.

`require_model_coordinate_unit` enforces the same selected unit for each model
head and rejects every other label before artifact loading. H and C therefore
admit a combined request under one explicit unit, with no implicit conversion.
`parse_request` checks all H/C models needed by a structurally valid
request before returning it; `nmrnet_inference.model.compose_net_input` repeats
the same check before building tensors. Tensor-parity tests temporarily inject
a test-only matching label for the element under test; they compare
transformations only and do not qualify or authorize prediction. Each gate can
close using one of the prior qualification routes below. The repository has
since adopted the operational convention documented above.
`tests/test_prediction_input.py::PredictionInputTests.test_non_angstrom_model_input_blocks_tensor_composition`
proves both heads reject a mismatched unit at tensor composition;
`tests/test_prediction_input.py::PredictionInputTests.test_request_admission_requires_units_for_every_present_model_head`
proves each present head is checked when one head is explicitly unqualified,
including a combined H/C request;
`tests/test_prediction_input.py::PredictionInputTests.test_context_atoms_do_not_select_heads_or_hide_a_present_head`
proves context-only input selects no head and a context atom cannot hide an
unqualified present C head;
`tests/test_prediction_input.py::PredictionInputTests.test_different_head_units_only_admit_matching_single_head_requests`
proves separate H/C unit qualifications are honored independently and a
combined request is rejected when one caller label cannot match both;
`tests/test_prediction_input.py::PredictionInputTests.test_composition_requires_exact_qualified_unit_and_allows_any_unit_label`
proves an explicitly mismatched head label is rejected before ordinary atom
validation. `tests/test_bond_distances.py` checks all four proposed C–H/C–Cl
bonds in each retained molecule against the NIST values documented in
`tests/fixtures/small_chloromethanes.txt`. Its 0.01 Å C–H and 0.04 Å C–Cl
tolerances are acceptance thresholds, not experimental uncertainties.
`make test/unit/bond-distances` and `make test/unit/prediction-input` are the
contained focused lanes for these checks.
An earlier `make prediction/tensor-parity` run passed 18 tests using only the
test-only label above; neither lane establishes the physical unit. The current
tree has a label-free per-head forward, request orchestrator and real model
constructor exercised separately on retained fixtures. Production artifact-
selector callbacks now connect to the orchestrator. The adopted angstrom unit
label is checked for H/C requests before the loader callback; parsing alone does
not qualify external molecular inputs beyond the stated coordinate contract.

The pinned upstream preprocessing constructs explicit-H RDKit molecules and
stores `mol2coords` results as `coordinates`. The helper embeds a conformer,
optimizes it with MMFF when embedding succeeds, then stores
`mol.GetConformer().GetPositions()` as float32:
https://github.com/numpde/fork-of-NMRNetplusplus/blob/3ba8b9c2f3d0a390d00685d238618345c6ab24d7/data_process/filter_nmr_data.py#L27-L39
https://github.com/numpde/fork-of-NMRNetplusplus/blob/3ba8b9c2f3d0a390d00685d238618345c6ab24d7/data_process/filter_nmr_data.py#L155-L171
https://github.com/numpde/fork-of-NMRNetplusplus/blob/3ba8b9c2f3d0a390d00685d238618345c6ab24d7/data_process/utils.py#L146-L192
RDKit's `GetBondLength` documentation defines conformer bond lengths in
angstroms, which supports the RDKit conformer-coordinate convention:
https://rdkit.org/docs/source/rdkit.Chem.rdMolTransforms.html
The paper corroborates RDKit conformer generation (§3.1; Appendix A, “3D
conformation generation”), but §3.1 identifies its constructed dataset as
NMRexp, so it does not establish the producer of this released NMRShiftDB2 file:
https://arxiv.org/html/2601.18524v1

The pinned `filter_nmr_data.py` describes a possible RDKit preprocessing route,
but not provenance for this member. Its defaults read
`data/raw_data/NMRexp_10to24_1_0811.parquet` and write
`data/raw_data/NMRexp_10to24_1_0811_H_max_chiral_1_max_atoms_70_ele_C_H_O_N_S_P_F_Cl_filtered.lmdb`,
not `data/nmrshiftdb2/All/valid.lmdb`:
https://github.com/numpde/fork-of-NMRNetplusplus/blob/3ba8b9c2f3d0a390d00685d238618345c6ab24d7/data_process/filter_nmr_data.py#L155-L176
https://github.com/numpde/fork-of-NMRNetplusplus/blob/3ba8b9c2f3d0a390d00685d238618345c6ab24d7/data_process/filter_nmr_data.py#L180-L203

The NMRexp paper documents `NMRexp_10to24_1` as Parquet structure-spectrum
records with SMILES, source-page metadata, NMR text/peaks and atom counts; its
schema does not document a coordinate field. Zenodo v1 lists
`NMRexp_10to24_1_0811.parquet` (MD5
`37ecb7f0ca391e67d4ab21c2cdc02a57`), and v2 lists
`NMRexp_10to24_1_1004.parquet` (MD5
`2f9ed8bc533364dfb9dce96c83703dd4`). Neither record lists the logged
`NMRexp_v0905/H|C` LMDBs or maps those paths to the Parquet files. These releases
show related dataset versions, not the bytes or coordinate producer of the
logged training inputs:
https://www.nature.com/articles/s41597-025-06245-5
https://zenodo.org/records/16809534
https://zenodo.org/records/17296666

An older NMRNet archive provides a related dataset comparison, not a producer
link. Its Methods say the prior `nmrshiftdb2-2018` dataset uses data “published
by Chio et al.” but attach the Kwon et al. (2020) citation, whose author list
includes Choi; they say it retains the train/test split from Jonas and Kuhn.
The same paragraph attributes RDKit `EmbedMolecule` and
`MMFFOptimizeMolecule` conformer generation to the new `nmrshiftdb2-2024`
dataset. It does not identify how the 2018 benchmark's coordinates were
generated. Jonas and Kuhn's 2019 source identifies NMRShiftDB revision 1624 and
describes a model based on bond-order connectivity, but no 3D coordinate
preprocessing or coordinate units:
https://link.springer.com/article/10.1186/s13321-019-0374-3
https://arxiv.org/html/2408.15681v1
Its supplement compares the 2018 and 2024 sets (Figure 3, pp. 9–10) without
adding a coordinate-generation account for 2018:
https://media.springernature.com/original/springer-static/esm/art%3A10.1038%2Fs43588-025-00783-z/MediaObjects/43588_2025_783_MOESM1_ESM.pdf
Zenodo v2 (record 10.5281/zenodo.14279498; `data.zip` MD5
`75fe82a1c9ef7a6749cbf3a3896f198f`) has an archive preview listing
`data/nmrshiftdb2_2018/All/valid.lmdb` at rounded size 21.1 MB and a separate
2024 `valid.lmdb` at 35.2 MB:
https://zenodo.org/records/14279498
https://zenodo.org/records/14279498/preview/data.zip?include_deleted=0
Zenodo v3 (record 10.5281/zenodo.19142375) reports the same `data.zip` MD5.
Its archive preview lists `data/nmrshiftdb2_2018/All/train.lmdb` at rounded
size 84.5 MB. The member path matches the fold-0 training log. The locally
inspected release archive (record 10.5281/zenodo.18232165) has a differently
rooted `data/nmrshiftdb2/All/train.lmdb` at exactly 84,492,288 bytes
(`artifacts/data-archive-members.json`, bound to that archive by
`artifacts/data-archive-inspection.json`), also rounding to 84.5 MB. This is a
path-and-size candidate only: neither record provides a per-member hash linking
its listed member to the logged training input.
https://zenodo.org/records/19142375
https://zenodo.org/records/19142375/preview/data.zip?include_deleted=0
The selected member here is `data/nmrshiftdb2/All/valid.lmdb`, exactly 21,131,264
bytes with SHA-256 `a72e17e3c9293b5852ef8d493f4ede23eb8b5cd8ca8e4c827a9bd8072e6a3a04`
(`artifacts/data.selection.json`, `artifacts/source-attribution.json`, and
`artifacts/reference-cpu-float32.json`). The directory roots differ; the
preview gives no member checksum or producer. Rounded sizes do not establish
byte identity.

For this exact release member, `artifacts/source-attribution.json` records the
original file-producing program and revision as unknown. `artifacts/release.json`
and `artifacts/data.selection.json` identify its Zenodo archive member;
`artifacts/reference-cpu-float32.json` binds the member bytes. The upstream
README associates the release with that Zenodo record but does not name a file
producer. These sources establish artifact identity, not that `mol2coords`
created its coordinates:
https://github.com/numpde/fork-of-NMRNetplusplus/blob/3ba8b9c2f3d0a390d00685d238618345c6ab24d7/README.md#L13-L16

Therefore the RDKit unit convention is supported, but its link to the exact
released coordinates is not proven. Keep the original producer and revision
unknown unless a direct producer-to-release link or retained producer evidence
is found. Producer attribution and empirical unit compatibility are separate
claims: the former may remain unknown even if the latter is qualified.

The H/C experiment-level `finetune.log` members are identified by path, size
and SHA-256 in `artifacts/reference-cpu-float32.json`; each contains training
argument records for folds 0–4. The manifest selects fold 0 for H and C
(`elements.H.fold` and `elements.C.fold`). The fold-0 records name
`./data/nmrshiftdb2_2018/All` as the labeled source and
`./data/NMRexp_v0905/H` for H or
`./data/NMRexp_v0905/C` for C as the respective
unlabeled source. The pinned `uninmr/tasks/uninmr.py` opens `train.lmdb` under
each path. The authenticated archive `data.zip` (SHA-256
`a6a23990cef1f0c28f835a4fdc9a5437d9d2f2bb13c758c07b7dc10c887c5b73`) was
inspected with `make weights/inspect ARCHIVE=data.zip`. The portable summary
receipt is `artifacts/data-archive-inspection.json` (SHA-256
`5de73d613702b2f0a3490c5196d413141a0e9eb71cb6201d5e4428200d6cffb1`). Raw
command output is not retained. The complete member listing is
`artifacts/data-archive-members.json` (SHA-256
`de16d977956cadf6432df6854df3cd656d352f68d09a34f2cc129a368f36ad6c`). It lists
`data/nmrshiftdb2/All/{train,valid}.lmdb`, ShiftDB-Lit train/validation members
and the NMRexp raw Parquet. No retained member hash or mapping binds those
differently named archive members to the logged training inputs or establishes
their coordinate producer. The selected and hashed `valid.lmdb` is a validation
member, not evidence of the exact coordinates used to train either checkpoint.

The prior qualification plan considered these evidence routes for establishing
the expected inference unit separately for each selected H/C checkpoint:

1. A publisher's input contract tied unambiguously to the selected checkpoint
   paths/hashes states the coordinate unit and any input-scale transformation.
2. An auditable checkpoint/run configuration and applicable preprocessing chain
   establish that same inference convention. Uniform pipeline evidence can
   establish this without reconstructing every historical training record.
The repository chose the operational convention based on the bounded evidence
above rather than claiming historical producer attribution. The test is
deliberately narrow and does not turn sampled evidence into an archive-wide
claim. The executable gate now expresses the chosen contract; any evidence of
a different producer convention requires revisiting it.

Prepared upstream clarification (not sent)
-----------------------------------------
The remaining missing fact is not answered by another local numerical rerun.
The following question is prepared for a release-author clarification; no issue,
message or other author contact has been sent. Posting it requires the
maintainer's explicit instruction to contact others.

For Zenodo release 18232165, what physical unit is expected for raw [N,3]
inference coordinates before the published centering/distance pipeline? Please
confirm separately for these exact fold-0 files in checkpoints.zip:

H: checkpoints/scratch_H_pretraining_molecular_unimol_large_atom_regloss_mae_lr_0.0004_bs1_4_bs2_16_wu_0.03_ep_10_wgt_16_T__ratio_4_16_20250930_033837/cv_seed_42_fold_0/checkpoint_last.pt
SHA-256 bc12977a19ddad7057c8c4d190203cdae8130b52e54f3ddbf37d875663de04e9
C: checkpoints/scratch_C_pretraining_molecular_unimol_large_atom_regloss_mae_lr_0.0004_bs1_4_bs2_16_wu_0.03_ep_10_wgt_16_T__ratio_4_16_20251004_182236/cv_seed_42_fold_0/checkpoint_last.pt
SHA-256 888c2fdcdd0379ded4c6de7322414fcf98658f4092adf8687a54329643c0376a

Does the same coordinate-unit convention apply to both checkpoints? Was any
coordinate scale conversion applied before the published model-input pipeline?
If so, which exact transformation should an inference caller apply? This asks
about coordinate units, not the ppm units of the output shifts. A released
validation-record match alone does not settle the expected convention for
external inputs.

The local request field is a caller declaration, not a check of physical scale:
the input has no bond graph from which the callable could verify the declaration.
When the gate closes, accept only the qualified unit spelling, reject
unsupported units, and never infer or convert. Unit qualification does not
establish producer identity, exact conformers, arbitrary-input chemistry or
model accuracy. Retained-coordinate parity can proceed independently, without
installing RDKit or generating geometry.

Scientific computation and exactness
===================================

Use upstream revision 3ba8b9c2f3d0a390d00685d238618345c6ab24d7 and the Uni-Core
source declaration already admitted by the image. The following order matters:

The expected tensors and predictions are qualified against the exact upstream
revision, Uni-Core source, inference image and model members identified by the
retained 001 reference. If a reference-producing source or dependency changes,
keep the old expectations and evidence, and require a separately reviewed,
version-keyed fixture set for the replacement. A missing matching fixture set
blocks qualification; do not regenerate expected values silently to make a new
version pass. This applies when a numerical reference producer changes, not to an
unrelated image rebuild. See 013 U21 and the producer identities in
`artifacts/reference-cpu-float32.json`.

1. Validate atom vocabulary, shape, bounds and numeric representability. Preserve
   every original atom index. Cast coordinates to float32 before centering.
   CroppingDataset does this cast even when no crop occurs; the adapter rejects
   oversize inputs and never enters random cropping.
   https://github.com/numpde/fork-of-NMRNetplusplus/blob/3ba8b9c2f3d0a390d00685d238618345c6ab24d7/uninmr/data/cropping_dataset.py#L27-L38
2. Subtract the coordinate mean in the upstream operation order and retain
   float32. Do not center float64 inputs first and assume numerical equivalence.
   https://github.com/numpde/fork-of-NMRNetplusplus/blob/3ba8b9c2f3d0a390d00685d238618345c6ab24d7/uninmr/data/normalize_dataset.py#L20-L26
3. Load the exact ordered dictionary and append [MASK] exactly as the task does.
   For this release there are 30 symbols before MASK and 31 afterwards, MASK=30.
   Tokenize atoms as int64 and add BOS/EOS. H/C output masks select all tokens
   of the corresponding element; special/padding positions are zero. The model
   sees all atoms, not only the atoms whose shifts are requested.
   https://github.com/numpde/fork-of-NMRNetplusplus/blob/3ba8b9c2f3d0a390d00685d238618345c6ab24d7/uninmr/tasks/uninmr.py#L174-L183
   https://github.com/numpde/fork-of-NMRNetplusplus/blob/3ba8b9c2f3d0a390d00685d238618345c6ab24d7/uninmr/data/select_token_dataset.py#L10-L40
   https://github.com/dptech-corp/Uni-Core/blob/ace6fae1c8479a9751f2bb1e1d6e4047427bc134/unicore/data/tokenize_dataset.py#L13-L28
4. Compute pairwise distances through the same SciPy distance_matrix operation,
   then cast to float32. BOS/EOS rows and columns in the distance matrix are
   zero. This is not the distance matrix of coordinates with zero-position
   special tokens inserted first. Edge IDs use token_i * dictionary_size +
   token_j, including the special tokens, and use int64.
   Separately prepend and append a zero coordinate 3-vector for BOS and EOS
   to the centered real-atom coordinates before right-padding src_coord.
   Check these two rows explicitly in the tensor oracle; they are distinct
   from padding added to reach a multiple of eight.
   https://github.com/numpde/fork-of-NMRNetplusplus/blob/3ba8b9c2f3d0a390d00685d238618345c6ab24d7/uninmr/data/distance_dataset.py#L20-L24
   https://github.com/numpde/fork-of-NMRNetplusplus/blob/3ba8b9c2f3d0a390d00685d238618345c6ab24d7/uninmr/data/distance_dataset.py#L74-L86
   https://github.com/numpde/fork-of-NMRNetplusplus/blob/3ba8b9c2f3d0a390d00685d238618345c6ab24d7/uninmr/data/pad_dataset.py#L104-L116
   https://github.com/numpde/fork-of-NMRNetplusplus/blob/3ba8b9c2f3d0a390d00685d238618345c6ab24d7/uninmr/tasks/uninmr.py#L366-L378
5. Preserve upstream right padding to a multiple of eight, even for batch 1.
   Pad tokens with dictionary PAD=0, masks/coordinates/distances/edge IDs with
   zero. Separate 128 original atoms, 130 logical tokens and 136 padded positions
   at the admitted maximum; resource bounds must use the padded size. Do not
   truncate to the logical-token bound after padding.
   https://github.com/dptech-corp/Uni-Core/blob/ace6fae1c8479a9751f2bb1e1d6e4047427bc134/unicore/data/pad_dataset.py#L12-L38
   https://github.com/numpde/fork-of-NMRNetplusplus/blob/3ba8b9c2f3d0a390d00685d238618345c6ab24d7/uninmr/data/pad_dataset.py#L96-L102
6. Instantiate the real UniMatModel and its real nmr_head with the qualified
   architecture and dictionary; load the selected full state with no missing,
   unexpected or shape-mismatched keys. Use the released configuration plus
   explicit qualified inference choices, not a second manually reconstructed
   network. Verify agreement with 001's resolved architecture. No fabricated
   task object, dataset, target tensor or loss is required.
   https://github.com/numpde/fork-of-NMRNetplusplus/blob/3ba8b9c2f3d0a390d00685d238618345c6ab24d7/uninmr/models/unimat.py#L143-L207
   https://github.com/numpde/fork-of-NMRNetplusplus/blob/3ba8b9c2f3d0a390d00685d238618345c6ab24d7/uninmr/tasks/uninmr.py#L461-L469
7. Execute model.eval() and no_grad() with CPUfloat32, batch 1 and the existing
   two-thread settings. Pass the per-element select_atom mask and explicitly
   call model(..., features_only=True, classification_head_name="nmr_head"),
   matching the qualified upstream invocation rather than forward's defaults.
   Forward selection occurs at that node head, preserving row order. Require
   one output row per selected atom and one scalar per row before inverse
   scaling. Retain an explicit index mapping back to the input atoms.
   https://github.com/numpde/fork-of-NMRNetplusplus/blob/3ba8b9c2f3d0a390d00685d238618345c6ab24d7/uninmr/losses/atom_regloss.py#L32-L35
   https://github.com/numpde/fork-of-NMRNetplusplus/blob/3ba8b9c2f3d0a390d00685d238618345c6ab24d7/uninmr/models/unimat.py#L209-L288
   https://github.com/numpde/fork-of-NMRNetplusplus/blob/3ba8b9c2f3d0a390d00685d238618345c6ab24d7/uninmr/tasks/uninmr.py#L471-L477
8. Apply that element's paired StandardScaler inverse once, preserving the
   Torch-input conversion and final float32 cast qualified in 001. Return finite
   ppm values only. Do not fit a scaler, hand-substitute its mean/scale in the
   production path, average folds, or compute training/accuracy losses.
   https://github.com/numpde/fork-of-NMRNetplusplus/blob/3ba8b9c2f3d0a390d00685d238618345c6ab24d7/uninmr/losses/atom_regloss.py#L75-L76
   https://github.com/numpde/fork-of-NMRNetplusplus/blob/3ba8b9c2f3d0a390d00685d238618345c6ab24d7/uninmr/utils/data_scaler.py#L32-L54

Compose upstream helpers/collaters where they express the transform clearly;
do not copy the task pipeline or hide dependence on label-bearing task setup.

Model reuse, containment and failure semantics
=============================================

The loaded scientific object owns one fixed element's model, dictionary and
scaler, and predicts that element's atoms in one molecule at tensor batch 1.
The composed callable loads H, predicts and releases H, then does the same for
C. Skip an absent element without an empty model call. Merge by original atom
index and return success only after both required predictions succeed; a C
failure cannot return the earlier H result as a successful answer.
The qualification loop also loads H once for all qualification fixtures,
releases it, then loads C once for those fixtures, skipping absent elements.
Exercise both loaded-model reuse and composed request calls. This permits
ordinary model reuse without a public batch protocol, daemon or concurrent
model copies.

Use the existing admitted immutable inference image: both embedded dependency
declarations must match, and its upstream revision must match the recorded
submodule. Verify extraction receipts and every consumed checkpoint/scaler/
dictionary member before trusted deserialization, and ensure deserialization
consumes those same verified bytes. `baseline_prepare.verified_member` currently
checks a member and returns its path; a later path reopen leaves a replacement or
in-place write gap. Deserialize a verified immutable byte buffer or a snapshot
protected from mutation through loading. A read-only bind mount does not stop
another writer to its backing file; a held descriptor prevents pathname
substitution but permits same-inode writes. In the contained qualification lane,
simulate both changes to the source after verification; require loading to retain
the verified bytes or reject the change. This protects against concurrent source
changes within the stated container/host boundary, not a hostile host or engine
administrator. Record the identities of the exact bytes consumed. Dictionary
ordering and full state compatibility remain hard admission requirements. A
pickle from a user input path is never a supported format. Record the actual
adapter/helper bytes alongside the image,
repository/source revisions, model identities and the hash of the same bounded
input buffer consumed by the parser. This extends the local path-returning helper
contract for a specific reason; it does not establish release authenticity from
a locally computed hash alone. See 013 U05 and:
https://github.com/numpde/nmrnet-repro/blob/e6a8a1b1a2dd5cb854d70277f40d3275945ce933/tools/baseline_prepare.py#L132-L163

The launcher owns the local engine and exact container lifecycle. All project
Python/tests/probes run contained: network=none, pull=never, nonzero UID/GID,
read-only root/inputs, cap-drop ALL, no-new-privileges, two CPU quota units,
4 GiB/no swap, 64 PIDs and baseline-bounded scratch. Grant only required inputs,
tools and dedicated output; no socket/home/credentials/workspace-root/devices.
Cancellation removes only the owned container, identified by this attempt; verify
that the engine reports it terminated. Local native-helper process retirement
alone does not prove engine-side work ended. This is a cancellation acceptance
check from 013 U14, not a new daemon; see the
[helper's retirement boundary](https://github.com/numpde/nmrnet-repro/blob/e6a8a1b1a2dd5cb854d70277f40d3275945ce933/tools/inference_native.sh#L7-L10).
Future acquisition still requires explicit command-line WLAN_INTERFACE;
prediction never acquires.

Use tools/container_guard.py for the new Python entrypoints and reusable
scientific modules, checking before dependency imports or side effects. The
launcher supplies NMRNET_IN_CONTAINER=1 explicitly and mounts and hashes the
actual shared guard source with the other executed files. This prevents accidental
direct host execution; engine grants enforce containment. Do not introduce a
second detection scheme. Exercise missing-marker rejection only in contained
subprocesses. The maintained test/repository convention suite automatically
includes nmrnet_inference/ sources and enforces hierarchical Make target names;
keep this slice within that existing policy.

Validate the whole bounded molecule input before any model forward. Inject a
C failure after H has succeeded and prove the composed callable raises instead
of returning partial success. The qualification harness owns its run evidence,
including input/model/tool identities and safe causal diagnostics; it must
preserve prior results and report failed or incomplete runs honestly. Reuse
existing evidence/publication mechanisms where applicable. A separate product
result.json/complete.json protocol and its storage-fault acceptance matrix are
deferred with the standalone runner. The prior design is preserved at the
revision linked in the priority correction above; do not create another
publication owner before the provider's actual boundary requires it.

Carry failures to each actual recipient through the channel they use; stderr is
only one possible surface. The callable must preserve useful safe causes; the
contained qualification harness carries them to developers/operators, and the
later provider adapter projects them for its actual recipients. Retained
failure evidence must preserve the causal facts needed for later authorized
diagnosis. Say whether input is invalid, an artifact is incompatible,
or execution/publication failed; identify the affected atom, field or artifact and
the non-secret cause where applicable; report actual effect state and a safe next
action when known. Keep classification, causal evidence and retry/final disposition
distinct. Propagate the fullest safe cause/context and add owned context across
wrappers and publication without replacing a specific failure with a generic code,
status or message.
Redact credentials, secret values and private molecular/host/session details at
each disclosure boundary without discarding adjacent useful diagnosis. Nonfinite
output fails; no device/precision/scaler/geometry/checkpoint fallback or error
framework. Retain qualification failures; omit private machine/session facts
from committed evidence. Review callable exceptions and the qualification
harness's actual diagnostic surfaces, including chained causes and effect state.
The coordinate callable returns to its authorized in-process caller and owns no
error logging or publication. Preserve loader/inference exceptions and causal chains,
which may contain sensitive evidence; never describe raw tracebacks as safe
public error text. A contained real-H/injected-C test carries a private sentinel
in the request and nested cause, checks unchanged exception/cause propagation,
no partial result, and no sentinel/request emitted to stdout/stderr. Admission
diagnostics independently exclude raw request data, including decoder context.

This is an explicit 2026-10-17 boundary correction to the broader diagnostic
acceptance in revision 40b8f81 of this note, following independent Use/code review.
That wording conflated causal preservation for an authorized caller with
disclosure to another recipient. The qualification harness handles public release
fixtures; it is not a private-request reporting interface. Provider recipient
projection, nested-cause redaction and secondary failures of that reporting
belong to 003's actual disclosure owner. They remain required there; they are not
claimed proven here. The current callable has no competing secondary reporting
operation. Qualification observation delivery still must succeed and the whole
lane must exit zero before evidence is retained; printing a packet is not success.
This applies 013 U08/U23 by actual owner, without adding a speculative formatter,
standalone CLI or new error protocol. Controlled admission diagnostics, causal
preservation and honest qualification failures remain 002 requirements.

Prospective parity and coverage proof
====================================

The qualification loop owns four separate single-molecule fixtures from 001's
two H and two C source records, with an explicit source-key/atom-index identity
crosswalk retained in its evidence. Those identities are not public input fields.
Before fixture iteration, assert the exact H and C source-key sets and the exact
set of 64 `(source_key, atom_index)` pairs from the pinned 001 reference; matching
the count alone can hide a substituted or omitted position. The population source
is `artifacts/reference-cpu-float32.json`, SHA-256
`8268206ad12003dea5ef57e1a7392de69325e110b54f2b91ee0f6314c4fef5ae`.
Add only the minimal cases needed where those records lack unlabelled eligible
atoms or an absent nucleus. These fixtures qualify preprocessing, output coverage
and agreement with the retained baseline; they do not establish broad chemical
accuracy.
Keep three proofs separate:

A. Tensor parity: for each original reference molecule, compare every shared
   model tensor against the real upstream dataset/collater, including float bits,
   dtypes, shapes, coordinate cast/centering order, distances, special tokens,
   edge IDs and padding. Source the oracle from verified original records. Its
   real training labels are allowed in test-only upstream preparation, never
   copied into the adapter request. Selection masks intentionally differ where
   source labels were absent; verify the production all-H/all-C mask against atom
   identities, and verify the oracle mask against original reference evidence.
   Exact shared-tensor parity is required before comparing predictions.

B. Existing-output parity: compare adapter outputs at the exact 64 labelled
   source record/atom positions with artifacts/reference-cpu-float32.json. This
   proves overlap with 001, not full output coverage. The production interface
   has no selection-mask override to make this test easier. Test-only diagnostic
   calls may compare the real upstream model at matched selection shapes, but
   such a diagnostic cannot substitute for testing the ordinary all-atom path.

C. Complete label-free coverage: independently count all supplied H and C atoms
   and assert exactly those original indices appear once, in order, with finite
   values. Include unlabelled eligible atoms and molecules with an absent nucleus;
   neither label availability nor label values may decide production coverage.
   Compare repeated independent calls and reordered fixture execution using the
   qualification crosswalk to expose leaked model state. Caller labels/target/mask
   fields are rejected, not consumed.

The `.work` run is not the only retained evidence for a published qualification
claim. The reviewed observation packet is
`artifacts/prediction-cpu-float32.json`. It records source keys and record hashes,
derived-request hashes, the exact expected population, per-tensor digest/shape/
dtype observations, complete H/C predictions and the 64-position comparison. It
binds fixture production to exact helper and upstream source bytes, model member
identities, image/runtime identity, numerical policy, and purpose. The source
artifact is marked `NOASSERTION`, so the packet omits its coordinate payload and
states the exact archive/member hash and rerun requirement. Keep raw run logs and
scratch under `.work`; publish no source data without an established distribution
basis. The packet records one historical execution and is immutable; qualification
commands produce new run evidence. Any later deterministic summary generated from
that packet needs paired write and no-write checks from the same canonical inputs
under 013 U20. This evidence policy follows 013 U06/U19 and preserves the
distinction between observation and rerun.

Numerical policy must be declared and reviewed before the first adapter/reference
output comparison. Shared tensors and matched-selection model execution start
with exact equality (ATOL=RTOL=0) in the same recorded image/CPU/thread runtime.
The initial all-atom overlap comparison also uses ATOL=RTOL=0. Unlike 001's two
identical executions, selecting additional atoms changes the node-head matrix
shape, which can change floating-point rounding even with identical encoder
features. Thus exact overlap is an explicit acceptance target, not an assumed
mathematical guarantee. The owner must inspect this risk before output comparison.
If a nonzero allowance is necessary, document a focused numerical justification
from the head operations, floating-point precision and paired inverse scaler;
have it independently reviewed before adopting a different threshold. Limit this
review to the affected operations. Do not reuse 001's label roundtrip allowance
as a prediction-parity bound or choose a threshold from the
observed failing discrepancy. An unexplained failure blocks qualification;
retain it and investigate the cause rather than relaxing the test to pass.
Any revised numerical contract needs a separately reviewed rationale and fresh
qualification, with the original failed attempt preserved.

Implementation and review checkpoints
=====================================

1. Provider boundary and input adaptation decision.
   Record the inspected API and sibling processor/input/result/failure owners
   with pinned sources and explain their applicability. Separate the Job text
   from admitted model input. Record how units, atoms and original indices reach
   the callable, and which chemistry decisions remain open if SMILES is offered.
   Do this before choosing a transport or result protocol.
   Acceptance: the next integration slice has a concrete boundary and explicit
   unresolved decisions, rather than an invented API model schema.

2. Real model loading and first reference execution.
   Connect verified dictionary/checkpoint/scaler snapshots to the real registered
   model and nmr_head. Use the released configuration and qualified CPUfloat32
   choices; require complete state compatibility and dictionary order. No task,
   dataset, labels or loss enter production. Keep H/C lifetimes sequential.
   Exercise real reference predictions in the contained scientific lane; freeze
   numerical policy before inspecting deltas. Apply the adopted ångström input
   contract; reference-fixture tests retain their explicit test-only controls.
   Acceptance: released state constructs through the production loading path
   and computes finite, correctly indexed reference outputs; input rejection
   precedes checkpoint/scaler deserialization. A load-only success does not
   qualify prediction or external input.

3. Scientific admission, parity, coverage and resources.
   Retain exact shared-tensor parity,
   the exact 64-position overlap population, independent complete H/C coverage,
   ordinary reuse, repeat/reordered calls and absent-head handling.
   Exercise 128 atoms / 136 padded positions with the real model and measure
   consumption against the existing container grants. Verify bounded same-buffer
   artifact reads, source growth, pathname replacement and same-inode mutation;
   size/digest must identify deserialized bytes.
   Acceptance: every scientific/input/artifact/resource gate passes under the
   declared policy. Unresolved units or unexplained numerical failures block
   qualification while earlier construction/fixture work can still proceed.

4. Actual contained callable boundary and errors.
   Exercise the composed callable through a maintained contained qualification
   entrypoint with its actual source/artifact mounts and grants. Reuse existing
   launchers; extend only for necessary inputs or evidence. Preserve container-only
   execution, image admission, offline inference and bounded resources. Verify
   engine-side termination for lifecycle ownership introduced by this work.
   Inject C failure after H success and prove no partial success is returned.
   Test unchanged nested causes, no partial result and no emitted private request
   sentinel at the authorized callable boundary. Preserve controlled admission
   errors and require whole-lane success before retaining public-fixture evidence.
   Provider recipient projection/redaction and its secondary reporting failures
   belong to 003; the boundary correction above records why.
   Acceptance: actual callable wiring, causal preservation and absence of
   unsolicited private output are proven, with public projection still deferred;
   a standalone prediction CLI/product file-publication protocol is deferred.

5. Qualification evidence, documentation and provider handoff.
   Run focused maintained tests and the final scientific qualification target.
   Independently audit the reference population, actual predictions, full-atom
   coverage, verified byte identities, containment/resource evidence and safe
   failure surfaces. Publish the compact reviewed packet described above.
   Document the callable, exact rerun command, limits and remaining provider work.
   Preserve historical 001 evidence; make coherent path-limited local commits.
   Acceptance: the provider can build on a qualified reusable scientific
   boundary, with its input adaptation and remaining integration decisions
   visible. Completing 002 does not claim an implemented or deployed provider.

Completion is falsifiable: the maintained contained qualification lane executes
the real composed callable with admitted qualified-unit atoms and coordinates,
gets each supplied H/C atom's finite ppm prediction at its original index,
and independently relates the results to the exact 001 population and model
bytes. All active scientific, input, artifact, resource, containment and safe
failure requirements above must pass. A separate prediction/run CLI and its
result.json/complete.json protocol are deferred, not counted as completed.
Final qualification record (2026-10-17)
=======================================

`make prediction/qualify` is the maintained contained rerun command. It runs
`make prediction/tensor-parity` and `make prediction/model-parity` sequentially
in the pinned offline inference image. The final run passed 23 tensor tests and
four real-callable tests. All 32 shared-tensor comparisons matched exactly by
dtype, shape and byte digest. Four retained fixtures produced 137 finite indexed
predictions (82 H, 55 C); the 64 historical reference positions matched exactly
at ATOL=RTOL=0. The callable admitted the chosen `angstrom` unit for both heads,
covered each eligible atom once, and produced equal repeated results in forward
and reversed fixture order. Both real released heads also predicted all 128
synthetic atom positions through the model prediction path (136 padded positions);
the composed-callable sample was 1,798,643,712 bytes and the full-lane peak was
1,859,960,832 bytes, both below the 4 GiB grant. Synthetic geometry qualifies
the capacity boundary only, not chemical validity. The lane also passed actual
H-then-C failure handling, artifact identity, and containment/resource checks
documented in the tests above. The packet binds its exact 64-position comparison
to `artifacts/reference-cpu-float32.json` (SHA-256
`8268206ad12003dea5ef57e1a7392de69325e110b54f2b91ee0f6314c4fef5ae`, 30,886
bytes), records eligible indices separately for H and C, and retains exact
artifact/member identities, source hashes, runtime, outputs and both scoped
resource readings. The run log is retained locally under
`.work/qualification/002-final-20261017/`.

This closes 002's stated reusable scientific boundary: the real composed callable
accepts explicitly unit-qualified atom coordinates and returns predictions tied
to original atom indices on the retained qualification population. It does not
claim broad chemical accuracy, reproduce a published ensemble result, establish
the original producer's coordinate units for every archive record, or supply a
SMILES-to-geometry/atom-mapping policy. RDKit-scale evidence and the NIST
CH3Cl/CH2Cl2 bond-distance test support the repository's explicit operational
`angstrom` contract, while archive-wide producer provenance remains unknown.
The released scaler emits scikit-learn's 1.5.2-to-1.8.0 version warning in the
recorded image; this limitation is visible and the observed contained comparison
passes. The data artifact's `NOASSERTION` license is why request coordinates are
not redistributed in the packet; a rerun must acquire the exact public archive
member and verify the recorded hashes. Provider/API integration and recipient-
appropriate error projection remain slice 003, not an open 002 acceptance item.

The final packet SHA-256 is
`3054ace5fb17b824e114c65c25e24389eca7551e38a0aece7f347f5b98f5fa75`.
Recheck it with `sha256sum artifacts/prediction-cpu-float32.json`. Future source,
image, artifact, or numerical-policy changes require a fresh qualification run
and a new packet.

Historical ten-review challenge (2026-10-14)
===========================================

This review concerned the earlier plan and does not review or qualify the
2026-10-17 priority correction.

Ten independent read-only reviewers examined the same plan revision,
69b607ce8755d84d7c55dde96094bfb5318fd861. Four distinct findings were accepted:
explicit BOS/EOS coordinate rows, the exact named-head invocation and output
shape, repository-relative execution-source identities, and unambiguous
per-element model lifetimes versus one-shot command composition. The head-call
omission was independently identified twice. These requirements are integrated
above; this review does not constitute implementation or scientific qualification.

One finding concerned exception masking by cleanup in the existing archive
extractor. It is outside this plan's change boundary: 002 consumes already
verified extracted artifacts and does not call or modify extraction. It was not
converted into an unrelated implementation task or treated as a defect fixed here.

Follow-up reviews checked the integrated corrections, including an explicit
C-failure-after-H-success proof, and found no further actionable plan issues.
Only this plan changed; no adapter implementation or scientific execution was
performed during the review.