12.13 Issue 58 canonical NNx wheel contract design¶
Status: Approved
Date: 2026-08-12
Decision: Add a fail-closed installation verifier that proves ml-eng-lab is testing the exact
thekaveh-nnx[lm]==0.2.0 named-release wheel, while retaining a validated, explicit local
editable-development mode.
12.13.1 Purpose¶
Issue #58 closes a provenance gap in the repository's NNx compatibility evidence. The runtime
manifests pin thekaveh-nnx[lm]==0.2.0, but the existing CI smoke only imports nnx and prints its
path. A matching distribution version does not prove that Python imported files owned by that
distribution: an editable checkout, PYTHONPATH, .pth file, or shadow package can supply the
same import name.
The defect is reproducible in the current local development environment. Distribution metadata
reports version 0.2.0, while PEP 610 metadata declares an editable sibling checkout and
nnx.__file__ resolves under that checkout. Those tests are useful upstream-development evidence,
but they are not proof of compatibility with the released wheel.
The change makes canonical-wheel identity an executable local and CI contract without prohibiting intentional NNx development. It does not change the NNx version, introduce a dependency lock or wheel hash, start Atlas, or create another required GitHub context.
12.13.2 Considered approaches¶
12.13.2.1 Validate only the distribution version¶
Checking importlib.metadata.version("thekaveh-nnx") == "0.2.0" is inexpensive but insufficient.
Editable installations carry the same version, and import shadowing can redirect nnx after the
distribution is installed. This approach is rejected.
12.13.2.2 Validate only inside the focused NNx workflow¶
Replacing the print-only smoke in pytest-nnx-surface would improve CI but leave direct local
pytest, make test, and the required pytest-repository signal able to report release compatibility
against an editable checkout. This approach is rejected.
12.13.2.3 Validate installation identity in local tests and both relevant CI jobs¶
This is the selected approach. A reusable standard-library verifier derives the expected pin from
the manifest, validates named-release or explicitly editable installation evidence, and is called
by the NNx surface suite. Both pytest-repository and pytest-nnx-surface select the NNx wheel
explicitly and run the canonical verifier after dependency installation and before their test
workloads. The existing required contexts remain unchanged.
12.13.2.4 Add a wheel hash lock¶
A PyPI wheel hash would provide stronger artifact identity, but it would introduce a second NNx pin surface and overlaps Issue #63's accepted dependency-lock and pinned-build-input scope. Issue
58 proves named-release wheel provenance rather than cryptographic byte identity. This approach is¶
deferred to Issue #63.
12.13.3 Exact pin source of truth¶
requirements.txt remains the only NNx version source. The verifier must locate exactly one
active requirement whose normalized distribution name is thekaveh-nnx, whose extras are exactly
[lm], whose operator is exactly ==, and whose version is 0.2.0. It rejects missing,
duplicate, ranged, editable, URL, VCS, or otherwise ambiguous declarations.
The implementation must not introduce a separately maintained version constant or NNx-specific
requirements file. Issue #61 owns a future version change; Issue #63 owns future hash locking. A
pin change in requirements.txt automatically changes the version the verifier expects, while
tests continue to enforce the exact requirement shape.
12.13.4 Canonical named-release mode¶
Canonical mode is the default. The verifier uses public importlib.metadata.Distribution APIs and
must prove all of the following:
- exactly one installed distribution normalized as
thekaveh-nnxis discoverable; - its normalized metadata name is
thekaveh-nnx; - its installed version equals the exact manifest pin;
direct_url.jsonis absent, rejecting editable, local-directory, local-archive, and VCS direct installations as non-canonical;- distribution files include
WHEEL,RECORD, andnnx/__init__.py; - the resolved
nnximport specification points to the same resolvednnx/__init__.pypath returned byDistribution.locate_file(); and - the owned package path is outside this repository checkout.
The verifier inspects the import specification before importing nnx, so a malicious or broken
shadow module is not executed merely to diagnose provenance. Symlinks are resolved before
comparison. Missing or malformed metadata fails closed.
Success output may name the public distribution, version, and mode. Failure output must not reveal the PEP 610 URL, editable checkout path, repository path, site-packages path, credentials, or other host-specific details.
12.13.5 Explicit editable-development mode¶
Intentional upstream NNx development uses one conspicuous opt-in:
NNX_ALLOW_EDITABLE=1 make test-nnx-surface
Only the exact value 1 enables editable mode; absent, empty, or any other value is canonical mode
or an invalid configuration. Editable mode is validation, not bypass. It still requires the exact
manifest and installed distribution versions, valid JSON PEP 610 metadata, a file: URL, and
dir_info.editable == true. The resolved nnx import must live beneath the declared editable
source directory. Non-editable direct URLs, VCS sources, malformed URLs, missing metadata, and
unrelated shadow packages remain failures.
The opt-in applies to local commands only. CI workflow, job, and step environments must not define
NNX_ALLOW_EDITABLE or PYTHONPATH. Documentation must label editable results as development
surface evidence and require canonical mode before recording released-wheel compatibility.
12.13.6 Test-suite integration¶
Add scripts/verify_nnx_install.py with pure validation helpers, a small evidence model, and a CLI
entry through python -m scripts.verify_nnx_install. Unit tests use fixture-owned fake
distributions and import specifications; they do not mutate the active Python installation.
The NNx surface suite invokes the verifier once through a session-scoped fixture before its API
tests run. This covers all entry points, including direct pytest, make test-nnx-surface, and the
complete make test collection. A local environment with an editable NNx checkout therefore fails
by default and passes only when the explicit editable mode validates that checkout.
Add make verify-nnx-install as the public canonical command. make test-nnx-surface continues to
run the focused tests; its session fixture supplies the installation gate rather than duplicating
the command in the target. The Make target, help text, and phony declaration are regression-tested.
12.13.7 CI installation and execution order¶
The existing pytest-repository and pytest-nnx-surface jobs retain their IDs, names, runners,
Python version, timeouts, cache manifests, dependency roles, and ordinary failure semantics. Their
runtime installation commands use python -m pip and add --only-binary=thekaveh-nnx when
installing requirements.txt. This forces pip to select a wheel for NNx without claiming that all
other dependencies are binary-only or hash-locked.
After every dependency-install command and immediately before the test workload, both jobs run:
make verify-nnx-install
The focused job then retains Ruff and make test-nnx-surface; the required repository job retains
make test. No later pip command may intervene between validation and the relevant tests. The
repository job makes provenance failures merge-blocking through its already-required
pytest-repository context, while pytest-nnx-surface remains the faster diagnostic signal.
The workflow contract must reject editable installs, direct NNx references, missing binary-only
selection, omitted or reordered validation, NNX_ALLOW_EDITABLE, PYTHONPATH, conditions,
services, containers, failure masking, extra steps, or a weakened test command. The verifier job's
narrow self-contract selector must run the new workflow regressions.
12.13.8 Regression coverage¶
Test-driven implementation must first demonstrate failures for the missing behavior and then cover:
- accepted canonical-wheel metadata with exact pin, owned files, and matching import origin;
- accepted editable metadata only under the exact local opt-in;
- wrong, missing, duplicate, ranged, URL, or incorrectly-extra'd manifest requirements;
- missing, duplicate, misnamed, or wrong-version installed distributions;
- any direct URL in canonical mode, and malformed or non-editable direct URLs in editable mode;
- missing
WHEEL,RECORD, ornnx/__init__.pyownership; - import mismatch, repository shadowing,
.pth/PYTHONPATHleakage, and symlink escape; - unknown override values and redaction of host paths and direct URLs from diagnostics; and
- mutation-resistant job step order, controls, commands, binary-only selection, and selector coverage.
Tests must not hard-code a repository-wide test count or inspect private dist._path state.
12.13.9 Documentation changes¶
Canonical documentation must describe the executable contract without duplicating ownership:
docs/dependency-contracts.mdreplaces its private-API/manual snippet with the public Make command, exact evidence semantics, and editable override.docs/nnx-library.mddistinguishes named-release evidence from upstream editable iteration and adds the canonical recovery command.docs/conventions.mdandCONTRIBUTING.mdadd the local/CI verification expectations.README.mdlinks the NNx section to the canonical contract and gives the explicit editable invocation without restating implementation details.docs/maintenance/overnight-2026-07-04.mdmarks OM-006 resolved only after live CI proves the contract.CHANGELOG.mdrecords the durable verifier, workflow, and editable-mode behavior.
The design and implementation plan are manifest-declared canonical pages. Generated site and wiki trees remain ignored derivatives. No architecture diagram change is needed because the existing focused NNx and complete pytest nodes remain accurate.
12.13.10 GitFlow rollout and GitHub records¶
Implementation proceeds on feature/issue-58-nnx-wheel-contract from synchronized develop.
After local TDD, task reviews, broad review, and full verification, open a ready feature-to-develop
pull request. Require green pytest-repository, atlas-consumer-policy, pytest-nnx-surface, and
every applicable check; record the live canonical verifier evidence.
Merge through a separate develop-to-main pull request, then restore ancestry with a
content-neutral main-to-develop synchronization pull request if required. Do not modify the
existing required-context set: pytest-repository already makes this contract blocking, and
atlas-consumer-policy remains independently required.
After release, check all Issue #58 acceptance criteria, add PR/test/runtime evidence, close the issue, move its project item to Done, update parent Issue #53, and verify one clean worktree, only the two long-lived branches, no open PRs, content-equivalent synchronized branches, and no ml-eng-lab, Atlas, JupyterHub, Ollama, or ComfyUI container. Unrelated containers remain untouched.
12.13.11 Acceptance criteria¶
The implementation is complete only when:
- CI proves the installed distribution version equals the exact NNx manifest pin;
- canonical mode proves the imported package is owned by a named-release wheel and rejects every direct/editable installation;
- editable PEP 610 metadata fails canonical CI and succeeds locally only through the exact, validated opt-in;
- tests demonstrate accepted and rejected requirement, distribution, metadata, ownership, import, redaction, and workflow cases with red-before-green evidence;
- both the required complete-suite job and focused NNx job run the verifier after binary-selected installation and immediately before tests;
- focused tests, complete tests, lint, repository verification, documentation checks, wiki generation, and live pull-request CI pass;
- documentation is synchronized across repository, site, and wiki surfaces;
- no NNx version, ruleset context, Atlas/runtime service, or unrelated container is changed; and
- GitFlow promotion, issue/project evidence, branch synchronization, and temporary-state cleanup are complete.