qig-stack 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,12 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *.egg-info/
4
+ .eggs/
5
+ build/
6
+ dist/
7
+ .pytest_cache/
8
+ .ruff_cache/
9
+ .venv/
10
+ venv/
11
+ *.whl
12
+ *.tar.gz
@@ -0,0 +1,96 @@
1
+ Metadata-Version: 2.4
2
+ Name: qig-stack
3
+ Version: 0.1.0
4
+ Summary: QIG toolchain metapackage — pins the mutually-tested latest set and ships the qig-doctor launch preflight (version gate + entry-point wiring gate + capability-slot report)
5
+ Project-URL: Homepage, https://braden.com.au
6
+ Project-URL: Repository, https://github.com/GaryOcean428/qig-stack
7
+ Project-URL: Documentation, https://github.com/GaryOcean428/qig-stack#readme
8
+ Author-email: Braden Lang <braden@garyocean.com>
9
+ License: MIT
10
+ Keywords: capability-contract,entry-points,launch-gate,metapackage,preflight,qig,reproducibility,self-wiring,version-gate
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Intended Audience :: Science/Research
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Topic :: Scientific/Engineering :: Physics
17
+ Requires-Python: >=3.10
18
+ Requires-Dist: packaging>=22
19
+ Requires-Dist: qig-bench==0.1.3
20
+ Requires-Dist: qig-compute==0.9.2
21
+ Requires-Dist: qig-consciousness==0.3.2
22
+ Requires-Dist: qig-core==2.12.2
23
+ Requires-Dist: qig-tokenizer==0.2.7
24
+ Requires-Dist: qig-warp==0.6.5
25
+ Requires-Dist: qigkernels==0.4.2
26
+ Provides-Extra: dev
27
+ Requires-Dist: pytest>=7.0; extra == 'dev'
28
+ Description-Content-Type: text/markdown
29
+
30
+ # qig-stack
31
+
32
+ The QIG toolchain **metapackage** + deterministic launch preflight.
33
+
34
+ `pip install qig-stack` installs the mutually-tested latest set of the QIG packages
35
+ (qig-compute / qig-warp / qig-core / qig-bench / qig-consciousness / qig-tokenizer /
36
+ qigkernels) at compatible versions — the whole "crystal" — and ships the `qig-doctor`
37
+ preflight.
38
+
39
+ ## qig-doctor — step-0 of every launcher
40
+
41
+ ```bash
42
+ qig-doctor # full preflight; exits 1 if any package is stale OR a slot is under-filled
43
+ qig-doctor --no-network # skip PyPI; contract snapshot + wiring report only
44
+ qig-doctor --json # machine-readable
45
+ qig-doctor --probe # also import-check each entry-point resolves (diagnostic, off the gate)
46
+ qig-doctor --deep # also call Tier-B describe() descriptors (imports packages)
47
+ ```
48
+
49
+ Three fail-closed jobs:
50
+
51
+ 1. **Version gate** — every stack package must be installed at PyPI-latest. `installed
52
+ < latest` is a LAUNCH BLOCKER (non-zero exit), per the "latest version, always
53
+ optimised" rule.
54
+ 2. **Wiring gate (Phase 2)** — enumerates the `qig.capabilities` entry-points the
55
+ installed packages self-register (Tier A: metadata-only, no import on the gate
56
+ path) and cross-checks them against the capability contract:
57
+ - **under-fill → FAIL**: a shipped provider that did not register its entry-point.
58
+ - **drift → WARN**: an entry-point the contract doesn't know, or one whose
59
+ `module:attr` moved off the contract probe.
60
+ 3. **Wiring report** — which capability slots are filled by what is installed (the
61
+ automated Gate-A lever inventory).
62
+
63
+ ## The capability contract
64
+
65
+ `src/qig_stack/contract.json` is the fixed lattice the stack crystallizes into — every
66
+ slot, the package primitive that fills it (`provider_pkg` + `module:attr` probe), the
67
+ latest-published version, and the camera-certification `cam_id`/`lever_id`. It is the
68
+ Genesis-kernel / E8-root analog: given the lattice + installed packages + version
69
+ policy, the wiring is determined — no per-experiment hand-wiring, no agentic guessing.
70
+
71
+ ## Self-wiring (Phase 2)
72
+
73
+ Each package declares the slots it fills in its own `pyproject.toml`:
74
+
75
+ ```toml
76
+ [project.entry-points."qig.capabilities"]
77
+ "SLOT-Q-QFI" = "qig_compute.qfi:qfi_from_mps_tangent_space"
78
+ ```
79
+
80
+ `qig-doctor` reads those declarations from installed metadata and confirms the crystal
81
+ assembled correctly before any compute spend. Entry-points assert only *"installed
82
+ package X fills slot Y via probe Z"* — certification stays in the camera-certification
83
+ registry under review control.
84
+
85
+ ## Design
86
+
87
+ - [self-wiring genesis design note](https://github.com/GaryOcean428/qig-verification/blob/development/docs/current/20260619-self-wiring-genesis-design-1.00W.md)
88
+ - [entry-point capability spec](https://github.com/GaryOcean428/qig-verification/blob/development/docs/current/20260619-qig-entry-point-capability-spec-1.00W.md)
89
+ - [Phase 2/3 design](https://github.com/GaryOcean428/qig-verification/blob/development/docs/plans/2026-06-30-qig-stack-self-wiring-phase23-design.md)
90
+
91
+ ## Development
92
+
93
+ ```bash
94
+ pip install pytest # tests import only qig_stack.doctor (pure stdlib)
95
+ pytest -q # contract schema + doctor unit tests (no network)
96
+ ```
@@ -0,0 +1,67 @@
1
+ # qig-stack
2
+
3
+ The QIG toolchain **metapackage** + deterministic launch preflight.
4
+
5
+ `pip install qig-stack` installs the mutually-tested latest set of the QIG packages
6
+ (qig-compute / qig-warp / qig-core / qig-bench / qig-consciousness / qig-tokenizer /
7
+ qigkernels) at compatible versions — the whole "crystal" — and ships the `qig-doctor`
8
+ preflight.
9
+
10
+ ## qig-doctor — step-0 of every launcher
11
+
12
+ ```bash
13
+ qig-doctor # full preflight; exits 1 if any package is stale OR a slot is under-filled
14
+ qig-doctor --no-network # skip PyPI; contract snapshot + wiring report only
15
+ qig-doctor --json # machine-readable
16
+ qig-doctor --probe # also import-check each entry-point resolves (diagnostic, off the gate)
17
+ qig-doctor --deep # also call Tier-B describe() descriptors (imports packages)
18
+ ```
19
+
20
+ Three fail-closed jobs:
21
+
22
+ 1. **Version gate** — every stack package must be installed at PyPI-latest. `installed
23
+ < latest` is a LAUNCH BLOCKER (non-zero exit), per the "latest version, always
24
+ optimised" rule.
25
+ 2. **Wiring gate (Phase 2)** — enumerates the `qig.capabilities` entry-points the
26
+ installed packages self-register (Tier A: metadata-only, no import on the gate
27
+ path) and cross-checks them against the capability contract:
28
+ - **under-fill → FAIL**: a shipped provider that did not register its entry-point.
29
+ - **drift → WARN**: an entry-point the contract doesn't know, or one whose
30
+ `module:attr` moved off the contract probe.
31
+ 3. **Wiring report** — which capability slots are filled by what is installed (the
32
+ automated Gate-A lever inventory).
33
+
34
+ ## The capability contract
35
+
36
+ `src/qig_stack/contract.json` is the fixed lattice the stack crystallizes into — every
37
+ slot, the package primitive that fills it (`provider_pkg` + `module:attr` probe), the
38
+ latest-published version, and the camera-certification `cam_id`/`lever_id`. It is the
39
+ Genesis-kernel / E8-root analog: given the lattice + installed packages + version
40
+ policy, the wiring is determined — no per-experiment hand-wiring, no agentic guessing.
41
+
42
+ ## Self-wiring (Phase 2)
43
+
44
+ Each package declares the slots it fills in its own `pyproject.toml`:
45
+
46
+ ```toml
47
+ [project.entry-points."qig.capabilities"]
48
+ "SLOT-Q-QFI" = "qig_compute.qfi:qfi_from_mps_tangent_space"
49
+ ```
50
+
51
+ `qig-doctor` reads those declarations from installed metadata and confirms the crystal
52
+ assembled correctly before any compute spend. Entry-points assert only *"installed
53
+ package X fills slot Y via probe Z"* — certification stays in the camera-certification
54
+ registry under review control.
55
+
56
+ ## Design
57
+
58
+ - [self-wiring genesis design note](https://github.com/GaryOcean428/qig-verification/blob/development/docs/current/20260619-self-wiring-genesis-design-1.00W.md)
59
+ - [entry-point capability spec](https://github.com/GaryOcean428/qig-verification/blob/development/docs/current/20260619-qig-entry-point-capability-spec-1.00W.md)
60
+ - [Phase 2/3 design](https://github.com/GaryOcean428/qig-verification/blob/development/docs/plans/2026-06-30-qig-stack-self-wiring-phase23-design.md)
61
+
62
+ ## Development
63
+
64
+ ```bash
65
+ pip install pytest # tests import only qig_stack.doctor (pure stdlib)
66
+ pytest -q # contract schema + doctor unit tests (no network)
67
+ ```
@@ -0,0 +1,64 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "qig-stack"
7
+ version = "0.1.0"
8
+ description = "QIG toolchain metapackage — pins the mutually-tested latest set and ships the qig-doctor launch preflight (version gate + entry-point wiring gate + capability-slot report)"
9
+ readme = "README.md"
10
+ license = { text = "MIT" }
11
+ requires-python = ">=3.10"
12
+ authors = [
13
+ { name = "Braden Lang", email = "braden@garyocean.com" },
14
+ ]
15
+ keywords = [
16
+ "qig", "metapackage", "preflight", "self-wiring", "capability-contract",
17
+ "entry-points", "version-gate", "launch-gate", "reproducibility",
18
+ ]
19
+ classifiers = [
20
+ "Development Status :: 4 - Beta",
21
+ "Intended Audience :: Science/Research",
22
+ "Intended Audience :: Developers",
23
+ "License :: OSI Approved :: MIT License",
24
+ "Programming Language :: Python :: 3",
25
+ "Topic :: Scientific/Engineering :: Physics",
26
+ ]
27
+
28
+ # The mutually-tested crystal: PyPI-latest at authoring (2026-06-30). Bumped as a
29
+ # set on each tested release; qig-doctor still resolves live latest at launch and
30
+ # fails closed if the installed venv is behind.
31
+ dependencies = [
32
+ "packaging>=22", # PEP 440-correct version comparison in the version gate
33
+ "qig-compute==0.9.2", # first release carrying qig.capabilities entry-points + born sampler
34
+ "qig-warp==0.6.5", # first release carrying qig.capabilities entry-points
35
+ "qig-core==2.12.2",
36
+ "qig-bench==0.1.3",
37
+ "qig-consciousness==0.3.2",
38
+ "qig-tokenizer==0.2.7",
39
+ "qigkernels==0.4.2",
40
+ ]
41
+
42
+ [project.optional-dependencies]
43
+ dev = ["pytest>=7.0"]
44
+
45
+ [project.scripts]
46
+ qig-doctor = "qig_stack.doctor:main"
47
+
48
+ [project.urls]
49
+ Homepage = "https://braden.com.au"
50
+ Repository = "https://github.com/GaryOcean428/qig-stack"
51
+ Documentation = "https://github.com/GaryOcean428/qig-stack#readme"
52
+
53
+ [tool.hatch.build.targets.wheel]
54
+ packages = ["src/qig_stack"]
55
+
56
+ [tool.hatch.build.targets.wheel.force-include]
57
+ "src/qig_stack/contract.json" = "qig_stack/contract.json"
58
+
59
+ [tool.hatch.build.targets.sdist]
60
+ include = ["src/qig_stack", "tests", "README.md", "pyproject.toml"]
61
+
62
+ [tool.pytest.ini_options]
63
+ pythonpath = "src"
64
+ testpaths = ["tests"]
@@ -0,0 +1,51 @@
1
+ """qig-stack -- the QIG toolchain metapackage + deterministic launch preflight.
2
+
3
+ `pip install qig-stack` pins the mutually-tested latest set of the QIG packages
4
+ (qig-compute / qig-warp / qig-core / qig-bench / qig-consciousness / qig-tokenizer /
5
+ qigkernels) and ships the `qig-doctor` preflight (version gate + entry-point wiring
6
+ gate + capability-slot report). See `qig_stack.doctor`.
7
+
8
+ The public symbols are exposed lazily (PEP 562) so importing the package does NOT
9
+ eagerly import `qig_stack.doctor` -- this keeps `python -m qig_stack.doctor` free of
10
+ the runpy "found in sys.modules" warning.
11
+ """
12
+
13
+ from __future__ import annotations
14
+
15
+ from typing import TYPE_CHECKING
16
+
17
+ __version__ = "0.1.0"
18
+
19
+ _LAZY = frozenset(
20
+ {
21
+ "main",
22
+ "build_report",
23
+ "is_behind",
24
+ "enumerate_capability_entrypoints",
25
+ "check_entrypoint_wiring",
26
+ }
27
+ )
28
+
29
+ __all__ = ["__version__", *sorted(_LAZY)]
30
+
31
+
32
+ def __getattr__(name: str):
33
+ if name in _LAZY:
34
+ from qig_stack import doctor
35
+
36
+ return getattr(doctor, name)
37
+ raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
38
+
39
+
40
+ def __dir__() -> list[str]:
41
+ return sorted(__all__)
42
+
43
+
44
+ if TYPE_CHECKING: # static-analysis visibility without an eager runtime import
45
+ from qig_stack.doctor import (
46
+ build_report,
47
+ check_entrypoint_wiring,
48
+ enumerate_capability_entrypoints,
49
+ is_behind,
50
+ main,
51
+ )
@@ -0,0 +1,146 @@
1
+ {
2
+ "doc": "QIG Stack Capability Contract",
3
+ "version": "1.01W",
4
+ "date": "2026-06-30",
5
+ "supersedes": "qig-verification:docs/current/20260619-qig-stack-capability-contract-1.00W.json (Phase-1 authored record)",
6
+ "principle": "Genesis-kernel deterministic self-assembly (vex-agent Core-8 / E8-root analog). The stack crystallizes into this FIXED lattice of capability slots; each slot is filled by a package primitive at latest-published version, cited to a camera-certification cert. With Phase 2 (entry-point self-registration) live, the wiring is DERIVED from installed metadata, not hand-authored.",
7
+ "authority": "PI directive 2026-06-19 (Phase 1) + 2026-06-30 (Phase 2/3 + born-sampler promotion); standing latest-version / step-0 lever-inventory rule (qig-verification/CLAUDE.md)",
8
+ "cert_registry": "qig-verification:docs/current/20260619-camera-certification-registry-1.00W.json",
9
+ "design_note": "qig-verification:docs/current/20260619-self-wiring-genesis-design-1.00W.md",
10
+ "entry_point_spec": "qig-verification:docs/current/20260619-qig-entry-point-capability-spec-1.00W.md",
11
+ "phase23_design": "qig-verification:docs/plans/2026-06-30-qig-stack-self-wiring-phase23-design.md",
12
+ "preflight": "qig_stack.doctor (console script: qig-doctor)",
13
+ "entry_point_group": "qig.capabilities",
14
+ "version_policy": {
15
+ "rule": "installed == latest-published (PyPI) at every launch; installed < latest is a LAUNCH BLOCKER (fail-closed, non-zero exit).",
16
+ "pin_exception": "Frozen reproducibility scripts keep pinned era-versions for bit-for-bit replay; this is never a reason to run a NEW launcher behind latest.",
17
+ "stack_packages_latest_at_authoring": {
18
+ "qig-compute": "0.9.2",
19
+ "qig-warp": "0.6.5",
20
+ "qig-core": "2.12.2",
21
+ "qig-bench": "0.1.3",
22
+ "qig-consciousness": "0.3.2",
23
+ "qig-tokenizer": "0.2.7",
24
+ "qigkernels": "0.4.2"
25
+ },
26
+ "note_on_latest": "These are a SNAPSHOT for reference only. qig_stack.doctor resolves latest live from PyPI at launch; do not treat this block as the source of truth -- the live query is. The qig-stack metapackage pins this exact set in pyproject.toml as the mutually-tested crystal."
27
+ },
28
+ "slot_status_legend": {
29
+ "CERTIFIED": "matched-cell equivalence certified once; cite the cam_id, never re-run",
30
+ "REFERENCE": "the exact reference path a cheap camera is certified against",
31
+ "PENDING": "uncertified cheap path; one-time cert must land before its results count",
32
+ "LEVER": "an efficiency lever (no measurement channel of its own)",
33
+ "CONDITIONAL": "usable only behind a controlled recheck at a calibration anchor"
34
+ },
35
+ "entry_point_gates": {
36
+ "under_fill": "FAIL (non-zero exit): a slot with provider_pkg set and shipped != false but no installed qig.capabilities entry-point (stale / mis-built / un-republished package).",
37
+ "drift": "WARN (non-fatal): an installed entry-point whose slot_id is not in the contract, or whose module:attr value differs from the slot probe.",
38
+ "exempt": "Slots with provider_pkg: null (engine-local, e.g. SLOT-GROUND-STATE/TeNPy) or shipped: false are exempt from under_fill."
39
+ },
40
+ "slots": [
41
+ {
42
+ "slot_id": "SLOT-GROUND-STATE",
43
+ "role": "prepare the lattice ground state psi that both channels read",
44
+ "channel": "state",
45
+ "provided_by": "qig-verification (engine) + TeNPy DMRG-complex",
46
+ "provider_pkg": null,
47
+ "primitive": "DMRG/MPS ground-state preparation vs ED",
48
+ "probe": "tenpy",
49
+ "cam_id": "CAM-STATE-DMRG-VS-ED",
50
+ "cert_status": "CERTIFIED",
51
+ "feasible_at": "L>=6 via MPS/DMRG"
52
+ },
53
+ {
54
+ "slot_id": "SLOT-Q-QFI",
55
+ "role": "quantum Fisher information (Q channel) -- exact, tensor-contractible",
56
+ "channel": "Q",
57
+ "provided_by": "qig-compute",
58
+ "provider_pkg": "qig-compute",
59
+ "primitive": "qfi.qfi_from_mps_tangent_space(psi_mps, L)",
60
+ "probe": "qig_compute.qfi:qfi_from_mps_tangent_space",
61
+ "cam_id": "CAM-QFI-MPS-TANGENT",
62
+ "cert_status": "CERTIFIED",
63
+ "feasible_at": "all L (O(chi^3) contraction, no sampling, zero error bar)",
64
+ "alternatives": ["CAM-QFI-DENSE-STREAMING", "CAM-QFI-BITFLIP", "CAM-QFI-SPARSE-NN", "CAM-QFI-SITE-PRUNE", "CAM-QFI-SITELOCAL"]
65
+ },
66
+ {
67
+ "slot_id": "SLOT-C-SUSCEPTIBILITY-REF",
68
+ "role": "classical / phase-blind Bhattacharyya fidelity-susceptibility (C channel) EXACT reference",
69
+ "channel": "C",
70
+ "provided_by": "qig-compute",
71
+ "provider_pkg": "qig-compute",
72
+ "primitive": "qfi.classical_fidelity_susceptibility(p_plus, p_minus, eps)",
73
+ "probe": "qig_compute.qfi:classical_fidelity_susceptibility",
74
+ "cam_id": "CAM-C-DENSE-REF",
75
+ "cert_status": "REFERENCE",
76
+ "feasible_at": "L<=5 ONLY (dense Born p over 2^N states; L=6 -> ~1.1 TB, infeasible)"
77
+ },
78
+ {
79
+ "slot_id": "SLOT-C-BORN-SAMPLER",
80
+ "role": "MPS Born-sampler -- the L=6-feasible C path (CERTIFIED via EXP-122 2026-06-19; PROMOTED to qig-compute 2026-06-30)",
81
+ "channel": "C",
82
+ "provided_by": "qig-compute (promoted from EXP-122 launcher born_C_score, byte-identical numerics)",
83
+ "provider_pkg": "qig-compute",
84
+ "primitive": "sampling.born_classical_fisher_score(psi_base, psi_p, psi_m, eps, M, seed): x ~ p(x) from MPS perfect (Ferris-Vidal) sampling, O(N chi^2)/sample; C = E_{x~p_base}[((log p+ - log p-)/2eps)^2] (PHASE-FREE classical-Fisher SCORE, estimator (c)). The Bhattacharyya form (estimator (a)) FAILS the 1/eps^2 variance test -- (c) is the certified estimator.",
85
+ "probe": "qig_compute.sampling:born_classical_fisher_score",
86
+ "cam_id": "CAM-C-BORN-MPS",
87
+ "cert_status": "CERTIFIED",
88
+ "shipped": true,
89
+ "promoted": "2026-06-30 from qig-verification/scripts/exp122_dmrg_complex.py:born_C_score (byte-identical). The frozen launcher keeps its inline copy for bit-for-bit reproducibility of the L=5 cert.",
90
+ "feasible_at": "L=6 (CERTIFIED at L=5: EXP-122 L=5 cert results/exp122/20260619_exp122_L5_born_cert.json @566b245 -- M=150k Delta=0.000373 bias PASS, sigma_D=0.00332 < D_sep/3=0.00473 variance PASS)."
91
+ },
92
+ {
93
+ "slot_id": "SLOT-SCREENING",
94
+ "role": "site pruning / screening lever (Yukawa shell cutoff)",
95
+ "channel": "lever",
96
+ "provided_by": "qig-warp",
97
+ "provider_pkg": "qig-warp",
98
+ "primitive": "prune_sites / screening_cutoff",
99
+ "probe": "qig_warp.screening:prune_sites",
100
+ "cam_id": "CAM-QFI-SITE-PRUNE",
101
+ "cert_status": "CERTIFIED"
102
+ },
103
+ {
104
+ "slot_id": "SLOT-EARLY-STOP",
105
+ "role": "convergence early-stop across the chi sub-ladder (8/16/24/32)",
106
+ "channel": "lever",
107
+ "provided_by": "qig-warp",
108
+ "provider_pkg": "qig-warp",
109
+ "primitive": "convergence.check_ci_stabilized / find_early_stop_point",
110
+ "probe": "qig_warp.convergence:check_ci_stabilized",
111
+ "lever_id": "LEV-CONVERGENCE-EARLYSTOP",
112
+ "cert_status": "LEVER"
113
+ },
114
+ {
115
+ "slot_id": "SLOT-RUNTIME-PRICING",
116
+ "role": "spend preflight before heavy launches",
117
+ "channel": "lever",
118
+ "provided_by": "qig-warp + chi-ladder pace-check",
119
+ "provider_pkg": "qig-warp",
120
+ "primitive": "bridge.predict_runtime (J-scaling) / chi-ladder pace-check",
121
+ "probe": "qig_warp.bridge:predict_runtime",
122
+ "lever_id": "LEV-CHI-PACE-CHECK",
123
+ "cert_status": "LEVER",
124
+ "caveat": "predict_runtime is J-scaling and is WRONG for L/chi-BOUND jobs at fixed J (EXP-122). For those, use the chi-ladder pace-check (LEV-CHI-PACE-CHECK)."
125
+ },
126
+ {
127
+ "slot_id": "SLOT-BLAS-PIN",
128
+ "role": "deterministic BLAS threading (API, not raw env-vars)",
129
+ "channel": "lever",
130
+ "provided_by": "qig-compute",
131
+ "provider_pkg": "qig-compute",
132
+ "primitive": "pin_blas_threads / single_thread_blas",
133
+ "probe": "qig_compute.blas:pin_blas_threads",
134
+ "lever_id": "LEV-BLAS-PIN",
135
+ "cert_status": "LEVER"
136
+ }
137
+ ],
138
+ "how_to_use": "Step-0 of every launcher: run `qig-doctor` (from the qig-stack package; qig-verification/scripts/qig_doctor.py is a back-compat shim). It (1) fails closed if any stack package is behind PyPI-latest, (2) fails closed on under-filled slots (a shipped provider that did not self-register its entry-point), and (3) enumerates which slots are filled by what is installed -- the automated Gate-A lever inventory. An experiment then cites the cam_id/lever_id for each slot it uses and never re-runs a matched-cell gate.",
139
+ "roadmap": {
140
+ "phase_1": "DONE -- fixed lattice (this contract) + qig_doctor.py fail-closed version preflight (qig-verification).",
141
+ "phase_2": "DONE 2026-06-30 -- each package self-registers its slots via [project.entry-points.'qig.capabilities'] (qig-compute, qig-warp); qig_stack.doctor derives wiring from entry-points (Tier-A metadata-only) with under-fill (FAIL) + drift (WARN) gates.",
142
+ "phase_3": "DONE 2026-06-30 -- qig-stack metapackage pins the mutually-tested latest set, houses the doctor + this contract, ships the qig-doctor console script; CI runs contract schema + doctor unit tests (no network).",
143
+ "born_sampler_promotion": "DONE 2026-06-30 -- SLOT-C-BORN-SAMPLER shipped:false -> true; born_C_score promoted to qig_compute.sampling.born_classical_fisher_score (byte-identical), gains an entry-point. CAM-C-BORN-MPS stays CERTIFIED.",
144
+ "activation": "entry-points go live in the installed crystal on each package's next PyPI release; cut qig-compute / qig-warp / qig-stack releases to activate (PI greenlight)."
145
+ }
146
+ }
@@ -0,0 +1,530 @@
1
+ #!/usr/bin/env python3
2
+ """qig_stack.doctor -- deterministic launch preflight (Genesis-kernel self-assembly check).
3
+
4
+ Step-0 of every launcher. Three jobs, all fail-closed:
5
+
6
+ 1. VERSION GATE -- every stack package must be installed at PyPI-latest.
7
+ installed < latest is a LAUNCH BLOCKER (non-zero exit), per
8
+ qig-verification/CLAUDE.md "Packages: latest version, always optimised".
9
+
10
+ 2. WIRING GATE (Phase 2) -- enumerate the `qig.capabilities` entry-points the
11
+ installed packages self-register (Tier A: metadata-only, NO import on the
12
+ fail-closed path) and cross-check them against the capability contract:
13
+ - UNDER-FILL -> FAIL (non-zero exit): a slot whose provider package is
14
+ shipped but did not register its entry-point (stale / mis-built package).
15
+ - DRIFT -> WARN: an installed entry-point the contract does not know, or
16
+ one whose module:attr moved off the contract probe.
17
+ ACTIVATION GRACE: if NO `qig.capabilities` entry-point is installed at all,
18
+ the feature is not yet activated in this venv (the providers have not
19
+ republished with entry-points) -- the gate reports PENDING and PASSES rather
20
+ than false-blocking every launch. Once any provider registers, the gate is
21
+ strict: a missing expected slot is then a real UNDER-FILL.
22
+
23
+ 3. WIRING REPORT -- which contract slots are filled by what is installed (the
24
+ automated Gate-A lever inventory).
25
+
26
+ The contract (bundled as `qig_stack/contract.json`) is the fixed lattice the
27
+ stack crystallizes into; this preflight checks the crystal formed correctly
28
+ before any compute spend.
29
+
30
+ Usage:
31
+ qig-doctor # full preflight, exits 1 if stale OR under-filled
32
+ qig-doctor --no-network # skip PyPI (contract snapshot + wiring only)
33
+ qig-doctor --json # machine-readable report
34
+ qig-doctor --probe # also import-check each entry-point resolves (off the gate)
35
+ qig-doctor --deep # also call Tier-B describe() descriptors (imports packages)
36
+ qig-doctor --contract PATH # override the bundled contract (testing)
37
+ """
38
+
39
+ from __future__ import annotations
40
+
41
+ import argparse
42
+ import importlib
43
+ import importlib.metadata as importlib_metadata
44
+ import json
45
+ import os
46
+ import sys
47
+ import urllib.error
48
+ import urllib.request
49
+ from dataclasses import asdict, dataclass, field
50
+ from pathlib import Path
51
+
52
+ try: # PEP 440-correct version comparison; `packaging` is a declared dependency.
53
+ from packaging.version import InvalidVersion, Version
54
+
55
+ _HAVE_PACKAGING = True
56
+ except ImportError: # pragma: no cover - defensive; packaging is in [project.dependencies]
57
+ _HAVE_PACKAGING = False
58
+
59
+ CAPABILITY_GROUP = "qig.capabilities"
60
+ PYPI_TIMEOUT_S = 10
61
+
62
+
63
+ def _contract_path(override: str | Path | None = None) -> Path:
64
+ """Locate the capability contract: explicit override > env var > bundled copy."""
65
+ if override:
66
+ return Path(override)
67
+ env = os.environ.get("QIG_STACK_CONTRACT")
68
+ if env:
69
+ return Path(env)
70
+ return Path(__file__).resolve().parent / "contract.json"
71
+
72
+
73
+ def latest_pypi_version(package: str, timeout: float = PYPI_TIMEOUT_S) -> str | None:
74
+ """Return the latest published version on PyPI, or None if unreachable.
75
+
76
+ Raises _PyPIAbsent on a definitive HTTP 404 (package/version genuinely not on
77
+ PyPI -- yanked or renamed), so the caller can distinguish that from a transient
78
+ network blip (which returns None -> fail-open).
79
+ """
80
+ url = f"https://pypi.org/pypi/{package}/json"
81
+ try:
82
+ with urllib.request.urlopen(url, timeout=timeout) as resp:
83
+ payload = json.load(resp)
84
+ except urllib.error.HTTPError as exc:
85
+ if exc.code == 404:
86
+ raise _PyPIAbsent(package) from exc
87
+ return None
88
+ except (urllib.error.URLError, TimeoutError, ValueError):
89
+ return None
90
+ info = payload.get("info", {})
91
+ version = info.get("version")
92
+ return version if isinstance(version, str) else None
93
+
94
+
95
+ class _PyPIAbsent(Exception):
96
+ """Definitive 'no such package/version on PyPI' (HTTP 404)."""
97
+
98
+
99
+ def installed_version(package: str) -> str | None:
100
+ try:
101
+ return importlib_metadata.version(package)
102
+ except importlib_metadata.PackageNotFoundError:
103
+ return None
104
+
105
+
106
+ def _parse_version(text: str) -> tuple[int, ...]:
107
+ """Zero-padding-agnostic release tuple (fallback only; drops local/pre/dev tails)."""
108
+ release = text.split("+", 1)[0]
109
+ parts: list[int] = []
110
+ for chunk in release.split("."):
111
+ digits = "".join(ch for ch in chunk if ch.isdigit())
112
+ if digits == chunk and digits: # pure numeric release component
113
+ parts.append(int(digits))
114
+ else: # a pre/post/dev tail (e.g. '1rc2', 'dev0') ends the release tuple
115
+ break
116
+ return tuple(parts)
117
+
118
+
119
+ def is_behind(installed: str, latest: str) -> bool:
120
+ """True iff `installed` is an older version than `latest` (PEP 440-correct)."""
121
+ if _HAVE_PACKAGING:
122
+ try:
123
+ return Version(installed) < Version(latest)
124
+ except InvalidVersion: # pragma: no cover - non-PEP440 string
125
+ pass
126
+ a, b = _parse_version(installed), _parse_version(latest)
127
+ n = max(len(a), len(b))
128
+ a += (0,) * (n - len(a))
129
+ b += (0,) * (n - len(b))
130
+ return a < b
131
+
132
+
133
+ # ───────────────────────── Phase-2: entry-point self-registration ─────────────────────────
134
+ def enumerate_capability_entrypoints() -> dict[str, str]:
135
+ """Tier A (CANONICAL): name -> "module:attr" for the qig.capabilities group.
136
+
137
+ Metadata-only -- enumerates DECLARATIONS without importing any package, so it
138
+ can never run package code and cannot inject non-determinism into a launch.
139
+ Requires the Python 3.10+ selectable entry_points(group=) API (requires-python>=3.10).
140
+ """
141
+ return {ep.name: ep.value for ep in importlib_metadata.entry_points(group=CAPABILITY_GROUP)}
142
+
143
+
144
+ @dataclass
145
+ class WiringIssue:
146
+ slot_id: str
147
+ kind: str # UNDER_FILL | DRIFT_UNKNOWN | DRIFT_MOVED
148
+ detail: str
149
+
150
+
151
+ def check_entrypoint_wiring(
152
+ slots: list[dict], declared: dict[str, str]
153
+ ) -> tuple[list[WiringIssue], list[WiringIssue]]:
154
+ """Cross-check declared qig.capabilities entry-points against the contract lattice.
155
+
156
+ Returns (underfill, drift). Pure function -- `declared` is injected so this is
157
+ unit-testable without a live environment.
158
+ - UNDER_FILL (FAIL): a slot with provider_pkg set and shipped != false but no
159
+ declared entry-point -- ONLY when the feature is activated (declared is
160
+ non-empty). An empty `declared` means the feature is not yet live in this
161
+ venv (providers not republished) -> no under-fill (see build_report's
162
+ wiring_activation = PENDING).
163
+ - DRIFT (WARN): a declared entry-point whose slot_id is not in the contract
164
+ (DRIFT_UNKNOWN), or whose value differs from the slot probe (DRIFT_MOVED).
165
+ """
166
+ underfill: list[WiringIssue] = []
167
+ drift: list[WiringIssue] = []
168
+ by_id = {s["slot_id"]: s for s in slots}
169
+ group_active = bool(declared)
170
+
171
+ if group_active:
172
+ for slot in slots:
173
+ provider = slot.get("provider_pkg")
174
+ shipped = slot.get("shipped", True)
175
+ expected = provider is not None and shipped is not False
176
+ if expected and slot["slot_id"] not in declared:
177
+ underfill.append(
178
+ WiringIssue(
179
+ slot["slot_id"],
180
+ "UNDER_FILL",
181
+ f"{provider} ships this slot but registered no '{CAPABILITY_GROUP}' "
182
+ f"entry-point (probe {slot.get('probe')!r}); stale or mis-built package.",
183
+ )
184
+ )
185
+
186
+ for name, value in declared.items():
187
+ slot = by_id.get(name)
188
+ if slot is None:
189
+ drift.append(
190
+ WiringIssue(name, "DRIFT_UNKNOWN", f"entry-point '{name}={value}' is not a contract slot_id")
191
+ )
192
+ elif slot.get("probe") and value != slot["probe"]:
193
+ drift.append(
194
+ WiringIssue(
195
+ name,
196
+ "DRIFT_MOVED",
197
+ f"entry-point value {value!r} != contract probe {slot['probe']!r}",
198
+ )
199
+ )
200
+
201
+ return underfill, drift
202
+
203
+
204
+ def _expected_slot_ids(slots: list[dict]) -> list[str]:
205
+ return [
206
+ s["slot_id"]
207
+ for s in slots
208
+ if s.get("provider_pkg") is not None and s.get("shipped", True) is not False
209
+ ]
210
+
211
+
212
+ @dataclass
213
+ class PackageCheck:
214
+ package: str
215
+ installed: str | None
216
+ latest: str | None
217
+ status: str # OK | STALE | MISSING | LATEST_UNKNOWN | PYPI_ABSENT
218
+
219
+
220
+ @dataclass
221
+ class SlotCheck:
222
+ slot_id: str
223
+ cite: str
224
+ cert_status: str
225
+ provided_by: str
226
+ filled: str # FILLED | MISSING | UNSHIPPED | PKG_ABSENT
227
+ entrypoint: str # DECLARED | ABSENT | DRIFT | EXEMPT | UNSHIPPED | PENDING
228
+
229
+
230
+ @dataclass
231
+ class Report:
232
+ contract: str
233
+ packages: list[PackageCheck] = field(default_factory=list)
234
+ slots: list[SlotCheck] = field(default_factory=list)
235
+ entrypoint_underfill: list[WiringIssue] = field(default_factory=list)
236
+ entrypoint_drift: list[WiringIssue] = field(default_factory=list)
237
+ wiring_activation: str = "N/A" # ACTIVE | PENDING | N/A
238
+ version_gate_passed: bool = True
239
+ wiring_gate_passed: bool = True
240
+
241
+
242
+ def check_packages(latest_versions: dict[str, str], use_network: bool) -> list[PackageCheck]:
243
+ checks: list[PackageCheck] = []
244
+ for package in sorted(latest_versions):
245
+ installed = installed_version(package)
246
+ if use_network:
247
+ try:
248
+ latest = latest_pypi_version(package)
249
+ except _PyPIAbsent:
250
+ checks.append(PackageCheck(package, installed, None, "PYPI_ABSENT"))
251
+ continue
252
+ else:
253
+ latest = latest_versions[package]
254
+ if installed is None:
255
+ status = "MISSING"
256
+ elif latest is None:
257
+ status = "LATEST_UNKNOWN"
258
+ elif is_behind(installed, latest):
259
+ status = "STALE"
260
+ else:
261
+ status = "OK"
262
+ checks.append(PackageCheck(package, installed, latest, status))
263
+ return checks
264
+
265
+
266
+ def _module_importable(probe: str | None) -> bool:
267
+ if not probe:
268
+ return False
269
+ top = probe.partition(":")[0].split(".")[0]
270
+ try:
271
+ importlib.import_module(top)
272
+ return True
273
+ except ImportError:
274
+ return False
275
+
276
+
277
+ def _probe_filled(probe: str | None) -> bool:
278
+ """A slot is filled if its probe imports. `module:attr` also checks the attr."""
279
+ if not probe:
280
+ return False
281
+ module_name, _, attr = probe.partition(":")
282
+ try:
283
+ module = importlib.import_module(module_name)
284
+ except ImportError:
285
+ return False
286
+ if attr:
287
+ return hasattr(module, attr)
288
+ return True
289
+
290
+
291
+ def check_slots(slots: list[dict], declared: dict[str, str]) -> list[SlotCheck]:
292
+ checks: list[SlotCheck] = []
293
+ group_active = bool(declared)
294
+ for slot in slots:
295
+ cite = slot.get("cam_id") or slot.get("lever_id") or "(uncited)"
296
+ provided_by = slot.get("provided_by", "")
297
+ probe = slot.get("probe")
298
+ provider = slot.get("provider_pkg")
299
+ shipped = slot.get("shipped", True)
300
+
301
+ # UNSHIPPED is a PACKAGE/wiring status, orthogonal to cert_status.
302
+ if shipped is False or (slot.get("cert_status") == "PENDING" and probe is None):
303
+ filled = "UNSHIPPED"
304
+ elif _probe_filled(probe):
305
+ filled = "FILLED"
306
+ elif _module_importable(probe):
307
+ filled = "MISSING" # package present, symbol gone
308
+ else:
309
+ filled = "PKG_ABSENT"
310
+
311
+ # entry-point dimension (Phase 2)
312
+ if provider is None:
313
+ entrypoint = "EXEMPT"
314
+ elif shipped is False:
315
+ entrypoint = "UNSHIPPED"
316
+ elif slot["slot_id"] in declared:
317
+ entrypoint = "DRIFT" if (probe and declared[slot["slot_id"]] != probe) else "DECLARED"
318
+ elif group_active:
319
+ entrypoint = "ABSENT"
320
+ else:
321
+ entrypoint = "PENDING" # feature not yet activated in this venv
322
+
323
+ checks.append(
324
+ SlotCheck(
325
+ slot_id=slot["slot_id"],
326
+ cite=cite,
327
+ cert_status=slot.get("cert_status", ""),
328
+ provided_by=provided_by,
329
+ filled=filled,
330
+ entrypoint=entrypoint,
331
+ )
332
+ )
333
+ return checks
334
+
335
+
336
+ class ContractError(Exception):
337
+ """The capability contract is missing, unreadable, or malformed."""
338
+
339
+
340
+ def _load_contract(contract_path: Path) -> dict:
341
+ try:
342
+ data = json.loads(Path(contract_path).read_text())
343
+ except FileNotFoundError as exc:
344
+ raise ContractError(f"contract not found at {contract_path}") from exc
345
+ except json.JSONDecodeError as exc:
346
+ raise ContractError(f"contract at {contract_path} is not valid JSON: {exc}") from exc
347
+ if "slots" not in data or "version_policy" not in data:
348
+ raise ContractError(
349
+ f"contract at {contract_path} missing required keys ('slots', 'version_policy')"
350
+ )
351
+ try:
352
+ data["version_policy"]["stack_packages_latest_at_authoring"]
353
+ except (KeyError, TypeError) as exc:
354
+ raise ContractError(
355
+ f"contract at {contract_path} missing version_policy.stack_packages_latest_at_authoring"
356
+ ) from exc
357
+ return data
358
+
359
+
360
+ def build_report(
361
+ contract_path: Path,
362
+ use_network: bool,
363
+ declared: dict[str, str] | None = None,
364
+ ) -> Report:
365
+ contract = _load_contract(Path(contract_path))
366
+ latest_versions = contract["version_policy"]["stack_packages_latest_at_authoring"]
367
+ slots = contract["slots"]
368
+ if declared is None:
369
+ declared = enumerate_capability_entrypoints()
370
+
371
+ report = Report(contract=str(contract_path))
372
+ report.packages = check_packages(latest_versions, use_network)
373
+ report.slots = check_slots(slots, declared)
374
+ report.entrypoint_underfill, report.entrypoint_drift = check_entrypoint_wiring(slots, declared)
375
+
376
+ if not _expected_slot_ids(slots):
377
+ report.wiring_activation = "N/A"
378
+ elif declared:
379
+ report.wiring_activation = "ACTIVE"
380
+ else:
381
+ report.wiring_activation = "PENDING"
382
+
383
+ report.version_gate_passed = all(
384
+ pkg.status in ("OK", "LATEST_UNKNOWN", "PYPI_ABSENT") for pkg in report.packages
385
+ )
386
+ report.wiring_gate_passed = not report.entrypoint_underfill
387
+ return report
388
+
389
+
390
+ def probe_entrypoints(declared: dict[str, str]) -> dict[str, bool]:
391
+ """Optional `--probe`: import-check that each entry-point module:attr resolves.
392
+
393
+ This IMPORTS packages, so it is OFF the fail-closed gate -- a diagnostic only.
394
+ """
395
+ return {name: _probe_filled(value) for name, value in declared.items()}
396
+
397
+
398
+ def deep_descriptors() -> list[dict]:
399
+ """Optional Tier-B `--deep`: call any `_descriptor` describe() entry-points.
400
+
401
+ IMPORTS + EXECUTES package code; FORBIDDEN on the fail-closed gate, behind --deep only.
402
+ """
403
+ out: list[dict] = []
404
+ for ep in importlib_metadata.entry_points(group=CAPABILITY_GROUP):
405
+ if ep.name != "_descriptor":
406
+ continue
407
+ try:
408
+ result = ep.load()()
409
+ if isinstance(result, list):
410
+ out.extend(result)
411
+ except Exception as exc: # noqa: BLE001 - diagnostic, never gates
412
+ out.append({"error": f"{ep.value}: {exc}"})
413
+ return out
414
+
415
+
416
+ _GLYPH = {
417
+ "OK": "ok ",
418
+ "STALE": "STALE",
419
+ "MISSING": "MISSING",
420
+ "LATEST_UNKNOWN": "lat?",
421
+ "PYPI_ABSENT": "404!",
422
+ "FILLED": "filled",
423
+ "UNSHIPPED": "UNSHIPPED",
424
+ "PKG_ABSENT": "pkg-absent",
425
+ "DECLARED": "ep-ok",
426
+ "ABSENT": "ep-ABSENT",
427
+ "DRIFT": "ep-DRIFT",
428
+ "EXEMPT": "exempt",
429
+ "PENDING": "ep-pending",
430
+ }
431
+
432
+
433
+ def print_report(report: Report, use_network: bool) -> None:
434
+ print(f"qig-doctor -- preflight against {report.contract}")
435
+ print(f" version source: {'PyPI (live)' if use_network else 'contract snapshot'}\n")
436
+ print(" VERSION GATE (installed must equal latest-published):")
437
+ for pkg in report.packages:
438
+ print(
439
+ f" [{_GLYPH[pkg.status]:>6}] {pkg.package:<18}"
440
+ f" installed={pkg.installed or '-':<28} latest={pkg.latest or '-'}"
441
+ )
442
+ print(f"\n WIRING REPORT (slots -> installed / entry-point) [activation: {report.wiring_activation}]:")
443
+ for slot in report.slots:
444
+ print(
445
+ f" [{_GLYPH[slot.filled]:>10}|{_GLYPH.get(slot.entrypoint, slot.entrypoint):>10}]"
446
+ f" {slot.slot_id:<26} {slot.cite:<22} ({slot.cert_status}) via {slot.provided_by}"
447
+ )
448
+
449
+ if report.entrypoint_drift:
450
+ print("\n WIRING DRIFT (WARN -- contract bump may be needed):")
451
+ for issue in report.entrypoint_drift:
452
+ print(f" [{issue.kind}] {issue.slot_id}: {issue.detail}")
453
+
454
+ absent = [p.package for p in report.packages if p.status == "PYPI_ABSENT"]
455
+ if absent:
456
+ print(f"\n NOTE: PyPI returned 404 for: {', '.join(absent)} (yanked/renamed? -- could not verify latest)")
457
+
458
+ stale = [p.package for p in report.packages if p.status in ("STALE", "MISSING")]
459
+ print()
460
+ if report.version_gate_passed:
461
+ print(" VERSION GATE: PASS")
462
+ else:
463
+ print(f" VERSION GATE: FAIL -- stale/missing: {', '.join(stale)}")
464
+ print(" -> LAUNCH BLOCKED. Update to latest published before launching:")
465
+ print(f" uv pip install -U {' '.join(stale)}")
466
+
467
+ if report.wiring_activation == "PENDING":
468
+ print(" WIRING GATE: PENDING ACTIVATION -- no qig.capabilities entry-points installed")
469
+ print(" (providers not yet republished with entry-points; not a blocker).")
470
+ elif report.wiring_gate_passed:
471
+ print(" WIRING GATE: PASS")
472
+ else:
473
+ under = ", ".join(i.slot_id for i in report.entrypoint_underfill)
474
+ print(f" WIRING GATE: FAIL -- under-filled slots: {under}")
475
+ print(" -> LAUNCH BLOCKED. A shipped provider did not self-register its")
476
+ print(" qig.capabilities entry-point (stale / mis-built package).")
477
+ for issue in report.entrypoint_underfill:
478
+ print(f" - {issue.slot_id}: {issue.detail}")
479
+
480
+
481
+ def main(argv: list[str] | None = None) -> int:
482
+ parser = argparse.ArgumentParser(
483
+ description="qig launch preflight (version gate + entry-point wiring gate + report)"
484
+ )
485
+ parser.add_argument(
486
+ "--no-network", action="store_true", help="skip PyPI; use contract snapshot"
487
+ )
488
+ parser.add_argument("--json", action="store_true", help="emit machine-readable JSON")
489
+ parser.add_argument(
490
+ "--probe", action="store_true", help="import-check each entry-point resolves (off the gate)"
491
+ )
492
+ parser.add_argument(
493
+ "--deep", action="store_true", help="call Tier-B describe() descriptors (imports packages)"
494
+ )
495
+ parser.add_argument("--contract", default=None, help="override the bundled contract path")
496
+ args = parser.parse_args(argv)
497
+
498
+ use_network = not args.no_network
499
+ try:
500
+ report = build_report(_contract_path(args.contract), use_network)
501
+ except ContractError as exc:
502
+ sys.stderr.write(f"qig-doctor: {exc}\n -> LAUNCH BLOCKED (preflight fail-closed).\n")
503
+ return 1
504
+
505
+ extras: dict[str, object] = {}
506
+ if args.probe:
507
+ extras["entrypoint_probe"] = probe_entrypoints(enumerate_capability_entrypoints())
508
+ if args.deep:
509
+ extras["descriptors"] = deep_descriptors()
510
+
511
+ if args.json:
512
+ payload = asdict(report)
513
+ payload.update(extras)
514
+ print(json.dumps(payload, indent=2))
515
+ else:
516
+ print_report(report, use_network)
517
+ if "entrypoint_probe" in extras:
518
+ print("\n ENTRY-POINT PROBE (import resolve-check):")
519
+ for name, ok in extras["entrypoint_probe"].items(): # type: ignore[union-attr]
520
+ print(f" [{'ok ' if ok else 'FAIL':>4}] {name}")
521
+ if "descriptors" in extras:
522
+ print("\n TIER-B DESCRIPTORS (--deep):")
523
+ for d in extras["descriptors"]: # type: ignore[union-attr]
524
+ print(f" {d}")
525
+
526
+ return 0 if (report.version_gate_passed and report.wiring_gate_passed) else 1
527
+
528
+
529
+ if __name__ == "__main__":
530
+ sys.exit(main())
@@ -0,0 +1,63 @@
1
+ """Schema tests for the bundled QIG Stack Capability Contract (no network)."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import json
6
+ from pathlib import Path
7
+
8
+ CONTRACT = Path(__file__).resolve().parent.parent / "src" / "qig_stack" / "contract.json"
9
+
10
+
11
+ def _load() -> dict:
12
+ return json.loads(CONTRACT.read_text())
13
+
14
+
15
+ def test_contract_present():
16
+ assert CONTRACT.exists(), "bundled contract.json missing from src/qig_stack/"
17
+
18
+
19
+ def test_contract_top_level_schema():
20
+ data = _load()
21
+ for key in ("doc", "version", "version_policy", "slots", "entry_point_group"):
22
+ assert key in data, f"contract missing top-level key: {key}"
23
+ assert data["entry_point_group"] == "qig.capabilities"
24
+ latest = data["version_policy"]["stack_packages_latest_at_authoring"]
25
+ for pkg in ("qig-compute", "qig-warp", "qig-core", "qig-bench"):
26
+ assert pkg in latest, f"version snapshot missing {pkg}"
27
+
28
+
29
+ def test_slots_well_formed():
30
+ data = _load()
31
+ seen: set[str] = set()
32
+ for slot in data["slots"]:
33
+ sid = slot["slot_id"]
34
+ assert sid not in seen, f"duplicate slot_id {sid}"
35
+ seen.add(sid)
36
+ assert "cert_status" in slot
37
+ assert slot.get("cam_id") or slot.get("lever_id"), f"{sid} cites no cam/lever id"
38
+ # provider_pkg is mandatory (may be null for engine-local slots)
39
+ assert "provider_pkg" in slot, f"{sid} missing provider_pkg"
40
+
41
+
42
+ def test_provider_slots_have_full_module_attr_probe():
43
+ """Every PyPI-provided, shipped slot must carry a module:attr probe == its entry-point."""
44
+ data = _load()
45
+ for slot in data["slots"]:
46
+ if slot.get("provider_pkg") and slot.get("shipped", True) is not False:
47
+ probe = slot.get("probe", "")
48
+ assert ":" in probe, f"{slot['slot_id']} probe {probe!r} is not module:attr"
49
+
50
+
51
+ def test_born_sampler_promoted():
52
+ data = _load()
53
+ born = next(s for s in data["slots"] if s["slot_id"] == "SLOT-C-BORN-SAMPLER")
54
+ assert born["shipped"] is True, "born sampler should be shipped after promotion"
55
+ assert born["provider_pkg"] == "qig-compute"
56
+ assert born["probe"] == "qig_compute.sampling:born_classical_fisher_score"
57
+ assert born["cert_status"] == "CERTIFIED"
58
+
59
+
60
+ def test_ground_state_is_engine_local():
61
+ data = _load()
62
+ gs = next(s for s in data["slots"] if s["slot_id"] == "SLOT-GROUND-STATE")
63
+ assert gs["provider_pkg"] is None, "ground-state slot is engine-local (no PyPI entry-point)"
@@ -0,0 +1,166 @@
1
+ """Unit tests for qig_stack.doctor -- version compare, slot fill, entry-point cross-check.
2
+
3
+ Network-free: the entry-point wiring is exercised by INJECTING a `declared` dict, so
4
+ these tests do not depend on what is installed in the environment.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import json
10
+
11
+ from qig_stack import doctor
12
+
13
+
14
+ def _contract_slots() -> list[dict]:
15
+ return json.loads(doctor._contract_path().read_text())["slots"]
16
+
17
+
18
+ def _all_expected_declared() -> dict[str, str]:
19
+ """The fully-wired crystal: every shipped, PyPI-provided slot declared at its probe."""
20
+ return {
21
+ s["slot_id"]: s["probe"]
22
+ for s in _contract_slots()
23
+ if s.get("provider_pkg") and s.get("shipped", True) is not False
24
+ }
25
+
26
+
27
+ # ───────────────────────── version gate (PEP 440-correct) ─────────────────────────
28
+ def test_version_comparison_logic():
29
+ assert doctor.is_behind("0.6.2", "0.9.1") is True
30
+ assert doctor.is_behind("0.9.1", "0.9.1") is False
31
+ assert doctor.is_behind("0.9.2", "0.9.1") is False
32
+ assert doctor.is_behind("0.2.0", "0.2.7") is True
33
+ assert doctor.is_behind("2.9.0", "2.12.2") is True # multi-digit minor
34
+
35
+
36
+ def test_version_comparison_prerelease_and_local():
37
+ # a dev/rc build is BEHIND its final release (the false-PASS the review caught)
38
+ assert doctor.is_behind("0.9.1.dev3", "0.9.1") is True
39
+ assert doctor.is_behind("0.9.1rc1", "0.9.1") is True
40
+ assert doctor.is_behind("0.9.2.dev8+g083281", "0.9.1") is False # dev of a newer release
41
+ # a post-release is AHEAD of its base release
42
+ assert doctor.is_behind("1.0.0.post1", "1.0.0") is False
43
+ # trailing-zero normalisation must not false-FAIL
44
+ assert doctor.is_behind("1.0", "1.0.0") is False
45
+ assert doctor.is_behind("2.12", "2.12.0") is False
46
+
47
+
48
+ # ───────────────────────── entry-point wiring gate (activation grace) ─────────────────────────
49
+ def test_wiring_clean_when_fully_declared():
50
+ slots = _contract_slots()
51
+ underfill, drift = doctor.check_entrypoint_wiring(slots, _all_expected_declared())
52
+ assert underfill == []
53
+ assert drift == []
54
+
55
+
56
+ def test_wiring_pending_when_nothing_declared():
57
+ """Empty group = feature not yet activated -> NO under-fill (grace, not a false-FAIL)."""
58
+ slots = _contract_slots()
59
+ underfill, drift = doctor.check_entrypoint_wiring(slots, {})
60
+ assert underfill == []
61
+ assert drift == []
62
+
63
+
64
+ def test_wiring_underfill_on_partial_activation():
65
+ """Once ANY provider registers, a missing expected slot is a real UNDER_FILL."""
66
+ slots = _contract_slots()
67
+ declared = _all_expected_declared()
68
+ missing = declared.pop("SLOT-Q-QFI") # qig-compute registered the rest but not this
69
+ assert missing
70
+ underfill, _ = doctor.check_entrypoint_wiring(slots, declared)
71
+ assert {i.slot_id for i in underfill} == {"SLOT-Q-QFI"}
72
+ assert all(i.kind == "UNDER_FILL" for i in underfill)
73
+
74
+
75
+ def test_wiring_exempts_engine_local_on_partial_activation():
76
+ slots = _contract_slots()
77
+ declared = _all_expected_declared()
78
+ declared.pop("SLOT-BLAS-PIN") # force partial activation
79
+ underfill, _ = doctor.check_entrypoint_wiring(slots, declared)
80
+ ids = {i.slot_id for i in underfill}
81
+ assert "SLOT-GROUND-STATE" not in ids # provider_pkg=null is never under-fill
82
+
83
+
84
+ def test_wiring_drift_unknown_slot():
85
+ slots = _contract_slots()
86
+ declared = _all_expected_declared()
87
+ declared["SLOT-MADE-UP"] = "qig_compute.nowhere:ghost"
88
+ _, drift = doctor.check_entrypoint_wiring(slots, declared)
89
+ assert any(i.kind == "DRIFT_UNKNOWN" and i.slot_id == "SLOT-MADE-UP" for i in drift)
90
+
91
+
92
+ def test_wiring_drift_moved_value():
93
+ slots = _contract_slots()
94
+ declared = _all_expected_declared()
95
+ declared["SLOT-Q-QFI"] = "qig_compute.somewhere_else:qfi_from_mps_tangent_space"
96
+ _, drift = doctor.check_entrypoint_wiring(slots, declared)
97
+ assert any(i.kind == "DRIFT_MOVED" and i.slot_id == "SLOT-Q-QFI" for i in drift)
98
+
99
+
100
+ # ───────────────────────── report assembly (offline) ─────────────────────────
101
+ def test_build_report_offline_fully_wired():
102
+ report = doctor.build_report(
103
+ doctor._contract_path(), use_network=False, declared=_all_expected_declared()
104
+ )
105
+ assert report.packages, "no package checks produced"
106
+ assert report.slots, "no slot checks produced"
107
+ assert report.wiring_activation == "ACTIVE"
108
+ assert report.wiring_gate_passed is True
109
+ born = next(s for s in report.slots if s.slot_id == "SLOT-C-BORN-SAMPLER")
110
+ assert born.entrypoint == "DECLARED"
111
+ gs = next(s for s in report.slots if s.slot_id == "SLOT-GROUND-STATE")
112
+ assert gs.entrypoint == "EXEMPT"
113
+
114
+
115
+ def test_build_report_pending_passes_wiring():
116
+ """Un-activated venv (no entry-points) -> PENDING, gate PASSES (no false block)."""
117
+ report = doctor.build_report(doctor._contract_path(), use_network=False, declared={})
118
+ assert report.wiring_activation == "PENDING"
119
+ assert report.wiring_gate_passed is True
120
+ assert report.entrypoint_underfill == []
121
+ born = next(s for s in report.slots if s.slot_id == "SLOT-C-BORN-SAMPLER")
122
+ assert born.entrypoint == "PENDING"
123
+
124
+
125
+ def test_build_report_partial_activation_fails_wiring():
126
+ declared = _all_expected_declared()
127
+ declared.pop("SLOT-SCREENING")
128
+ report = doctor.build_report(doctor._contract_path(), use_network=False, declared=declared)
129
+ assert report.wiring_activation == "ACTIVE"
130
+ assert report.wiring_gate_passed is False
131
+ assert {i.slot_id for i in report.entrypoint_underfill} == {"SLOT-SCREENING"}
132
+
133
+
134
+ # ───────────────────────── malformed contract (fail-closed, no traceback) ─────────────────────────
135
+ def test_malformed_contract_raises_contract_error(tmp_path):
136
+ bad = tmp_path / "broken.json"
137
+ bad.write_text("{ not valid json ")
138
+ import pytest
139
+
140
+ with pytest.raises(doctor.ContractError):
141
+ doctor.build_report(bad, use_network=False, declared={})
142
+
143
+
144
+ def test_missing_keys_contract_raises_contract_error(tmp_path):
145
+ bad = tmp_path / "incomplete.json"
146
+ bad.write_text(json.dumps({"doc": "x", "slots": []})) # no version_policy
147
+ import pytest
148
+
149
+ with pytest.raises(doctor.ContractError):
150
+ doctor.build_report(bad, use_network=False, declared={})
151
+
152
+
153
+ def test_main_offline_runs(capsys):
154
+ rc = doctor.main(["--no-network", "--contract", str(doctor._contract_path())])
155
+ out = capsys.readouterr().out
156
+ assert "VERSION GATE" in out and "WIRING" in out
157
+ assert rc in (0, 1)
158
+
159
+
160
+ def test_main_malformed_contract_returns_1(tmp_path, capsys):
161
+ bad = tmp_path / "broken.json"
162
+ bad.write_text("nonsense")
163
+ rc = doctor.main(["--no-network", "--contract", str(bad)])
164
+ err = capsys.readouterr().err
165
+ assert rc == 1
166
+ assert "LAUNCH BLOCKED" in err