qig-stack 0.1.0__py3-none-any.whl

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.
qig_stack/__init__.py ADDED
@@ -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
+ }
qig_stack/doctor.py ADDED
@@ -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,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,7 @@
1
+ qig_stack/__init__.py,sha256=_Uoofejm1xurIsYsNkXyknkokK47pnXwcEqbhDKOo-U,1422
2
+ qig_stack/doctor.py,sha256=N5di8W3g7C-kJfjVq5Dv1i_B-nSG19YhBBOHc_kZUtw,20324
3
+ qig_stack/contract.json,sha256=67e94EN8PS_IJzbxQvReSDbxD2K-jA73VjBqDmsuQT4,9504
4
+ qig_stack-0.1.0.dist-info/METADATA,sha256=NgCW66dVKT00ja094nGqbyuyQ7zduj5yzbotB5_W4Zo,4539
5
+ qig_stack-0.1.0.dist-info/WHEEL,sha256=mffPy8wBnZQn2VnJUU5jE99KsxaSfiyMHV9Yt0aLVxs,87
6
+ qig_stack-0.1.0.dist-info/entry_points.txt,sha256=ShiiObo3EgrCZqJzLCzj3nueixQPu7x_SWlGq4VxMCw,53
7
+ qig_stack-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.30.1
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ qig-doctor = qig_stack.doctor:main