Skip to content

Commit 08fea71

Browse files
ericchansenCopilot
andcommitted
fix(packaging): enforce release artifact contract
Ship only the approved generated SN2 reference resource and make its provenance and integrity explicit. Require configured roots for scientific data that cannot be redistributed. Validate wheel and sdist allowlists, rebuild from the sdist, and smoke-test the installed package before publication. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
1 parent 754b790 commit 08fea71

51 files changed

Lines changed: 1443 additions & 304 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitattributes

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
q2mm/data/sn2/*.json text eol=lf
2+
q2mm/data/sn2/*.txt text eol=lf
3+
q2mm/data/sn2/*.xyz text eol=lf
4+
q2mm/data/sn2/*.npy -text
5+
q2mm/data/sn2/*.npz -text

.github/workflows/publish.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ jobs:
2626
- name: Build sdist and wheel
2727
run: python -m build
2828

29+
- name: Validate artifact and installed-data contracts
30+
run: python scripts/check_release_artifacts.py --dist-dir dist
31+
2932
- name: Verify version matches tag
3033
run: |
3134
TAG="${GITHUB_REF#refs/tags/v}"

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ psi4_generation.log
55
psi*.clean
66

77
# ── Generated Psi4 logs (large, regenerated by generate_qm_data.py) ──
8-
examples/sn2-test/qm-reference/psi4-output*.dat
8+
examples/sn2-test/psi4-output*.dat
99
examples/rh-enamide/psi4_reference/
1010

1111
# ── External validation data (large, not redistributable) ──

MANIFEST.in

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
include LICENSE
2+
include README.md
3+
include pyproject.toml
4+
graft q2mm
5+
6+
prune .copilot
7+
prune .github
8+
prune .vscode
9+
prune docs
10+
prune examples
11+
prune scripts
12+
prune test
13+
prune validation
14+
15+
exclude .gitignore
16+
exclude .gitattributes
17+
exclude .pre-commit-config.yaml
18+
exclude AGENTS.md
19+
exclude CHANGELOG.md
20+
exclude CONTRIBUTING.md
21+
exclude properdocs.yml
22+
23+
global-exclude *.py[cod]
24+
global-exclude __pycache__

docs/getting-started.md

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,31 @@ cd q2mm
3737
pip install -e ".[dev]" # editable install with dev tools
3838
```
3939

40+
### External data for published systems
41+
42+
Q2MM does not distribute the licensed or third-party datasets used by the
43+
published transition-state systems. Configure their locations before running
44+
those systems:
45+
46+
| Variable | Required by | Value |
47+
|----------|-------------|-------|
48+
| `Q2MM_RH_ENAMIDE` | Rh-enamide | Directory containing `mm3.fld` and `rh_enamide_training_set/` |
49+
| `Q2MM_SUPPORTING_INFO` | Heck relay; Pd/Rh conjugate; Pd-allyl | Root of the extracted Wahlers/Rosales supporting information |
50+
| `Q2MM_MM3_BASE` | Pd-allyl; Pd/Rh conjugate | Licensed `mm3_base.fld` file |
51+
52+
For example, in Bash:
53+
54+
```bash
55+
export Q2MM_RH_ENAMIDE=/path/to/q2mm/examples/rh-enamide
56+
export Q2MM_SUPPORTING_INFO=/path/to/q2mm/validation/supporting-info
57+
export Q2MM_MM3_BASE=/path/to/mm3_base.fld
58+
```
59+
60+
In PowerShell, use `$env:Q2MM_RH_ENAMIDE = "..."` (and likewise for the
61+
other variables). Missing or invalid roots raise an error naming the exact
62+
variable or `ExternalDataRoots` field to configure; Q2MM never searches above
63+
the installed package.
64+
4065
---
4166

4267
## QM/MM backends
@@ -72,14 +97,15 @@ cd q2mm
7297
```python
7398
from q2mm.io import GaussLog, load_mm3_fld
7499
from q2mm.models import Q2MMMolecule
100+
from q2mm.resources import sn2_reference_dir
75101

76102
# Parse a Gaussian log for the QM Hessian (matrix of energy second derivatives)
77103
log = GaussLog("examples/ethane/TS.log")
78104
structure = log.structures[0]
79105
print(f"Atoms: {structure.num_atoms}, Hessian shape: {structure.hess.shape}")
80106

81107
# Load an XYZ geometry into the unified molecule model
82-
mol = Q2MMMolecule.from_xyz("examples/sn2-test/qm-reference/ch3f-optimized.xyz")
108+
mol = Q2MMMolecule.from_xyz(sn2_reference_dir() / "ch3f-optimized.xyz")
83109
print(f"Q2MMMolecule atoms: {mol.n_atoms}")
84110

85111
# Load an MM3 force field
@@ -105,4 +131,3 @@ q2mm/
105131
1. Follow the [Tutorial](tutorial.md) for a complete parameterization walkthrough
106132
2. Read [Theory & Methods](how-it-works/theory.md) to understand the pipeline
107133
3. See [Platform Support](platform-support.md) for GPU and backend setup
108-

docs/how-it-works/architecture.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,8 @@ q2mm/
192192
├── constants.py # Physical constants
193193
├── elements.py # Periodic table data
194194
├── geometry.py # Geometry helpers (distances, angles, alignment)
195+
├── resources.py # Installed scientific-resource lookup and integrity checks
196+
├── data/sn2/ # Approved CH3F/SN2 package resource + provenance manifest
195197
├── benchmark_runner.py # Canonical convergence benchmark runner (backs q2mm.benchmark)
196198
├── systems.py # Benchmark system registry (SYSTEMS, SystemData, load_system)
197199
@@ -270,6 +272,30 @@ q2mm/
270272
└── tables.py # Formatted table output
271273
```
272274

275+
### Release and scientific-data boundary
276+
277+
Q2MM's release artifacts use an explicit data contract:
278+
279+
- Wheels contain Python modules, `py.typed`, distribution metadata, and only
280+
the generated CH3F/SN2 resource in `q2mm/data/sn2/`.
281+
- Source distributions contain only the inputs needed to build that wheel.
282+
Tests, examples, documentation, workflows, validation data, and raw
283+
third-party outputs are repository-only.
284+
- `q2mm.resources.sn2_reference_dir()` resolves the built-in data through
285+
`importlib.resources`, so source checkouts and installed wheels use the same
286+
canonical files. `manifest.json` records provenance, license, size, and
287+
SHA-256 for every scientific payload file.
288+
- Rh-enamide, dissertation supporting information, and the licensed MM3 base
289+
force field are not distributed. Pass `ExternalDataRoots` to
290+
`load_system(data_roots=...)`, or configure `Q2MM_RH_ENAMIDE`,
291+
`Q2MM_SUPPORTING_INFO`, and `Q2MM_MM3_BASE`. Loaders never search above the
292+
installed package or substitute a tracked force field.
293+
294+
The publish workflow runs `scripts/check_release_artifacts.py` before upload.
295+
It validates both manifests, rebuilds the wheel from the sdist, compares wheel
296+
payloads, installs the rebuilt wheel into a clean environment, and exercises
297+
the import, CLI, resource integrity, and built-in CH3F system.
298+
273299
### Dependency flow
274300

275301
```mermaid

docs/systems/heck-relay.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,10 @@ Heck relay identifies a cross-engine boundary for literature transfer that canno
179179

180180
## Reproduce
181181

182+
Configure `Q2MM_SUPPORTING_INFO` as described in
183+
[External data for published systems](../getting-started.md#external-data-for-published-systems)
184+
before running this command.
185+
182186
```bash
183187
python -m q2mm.diagnostics.cli --system heck-relay --backend jax --optimizer optax-adam-cosine
184188
```

docs/systems/pd-allyl.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,10 @@ The negative R² reflects incomplete composed-force-field transfer, not a proble
144144

145145
## Reproduce
146146

147+
Configure both `Q2MM_SUPPORTING_INFO` and `Q2MM_MM3_BASE` as described in
148+
[External data for published systems](../getting-started.md#external-data-for-published-systems)
149+
before running this command.
150+
147151
```bash
148152
python -m q2mm.diagnostics.cli --system pd-allyl --backend jax --optimizer optax-adam-cosine
149153
```

docs/systems/pd-conjugate.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,10 @@ The negative R² reflects a transfer gap in the composed FF workflow.
143143

144144
## Reproduce
145145

146+
Configure both `Q2MM_SUPPORTING_INFO` and `Q2MM_MM3_BASE` as described in
147+
[External data for published systems](../getting-started.md#external-data-for-published-systems)
148+
before running this command.
149+
146150
```bash
147151
python -m q2mm.diagnostics.cli --system pd-conjugate --backend jax --optimizer optax-adam-cosine
148152
```

docs/systems/rh-conjugate.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,10 @@ The negative R² reflects a real transfer gap in the composed FF workflow.
158158

159159
## Reproduce
160160

161+
Configure both `Q2MM_SUPPORTING_INFO` and `Q2MM_MM3_BASE` as described in
162+
[External data for published systems](../getting-started.md#external-data-for-published-systems)
163+
before running this command.
164+
161165
```bash
162166
python -m q2mm.diagnostics.cli --system rh-conjugate --backend jax --optimizer optax-adam
163167
```

0 commit comments

Comments
 (0)