shotgate 0.2.0__tar.gz → 0.2.2__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.
Files changed (98) hide show
  1. shotgate-0.2.2/.github/workflows/dockerhub-mirror.yml +91 -0
  2. {shotgate-0.2.0 → shotgate-0.2.2}/.github/workflows/hardware-validation.yml +26 -2
  3. {shotgate-0.2.0 → shotgate-0.2.2}/.github/workflows/pypi-smoke.yml +10 -1
  4. {shotgate-0.2.0 → shotgate-0.2.2}/.github/workflows/release.yml +41 -0
  5. {shotgate-0.2.0 → shotgate-0.2.2}/CHANGELOG.md +56 -4
  6. {shotgate-0.2.0 → shotgate-0.2.2}/CONTRIBUTING.md +2 -2
  7. {shotgate-0.2.0 → shotgate-0.2.2}/Containerfile +1 -1
  8. {shotgate-0.2.0 → shotgate-0.2.2}/Makefile +2 -2
  9. {shotgate-0.2.0 → shotgate-0.2.2}/PKG-INFO +6 -2
  10. {shotgate-0.2.0 → shotgate-0.2.2}/README.md +5 -1
  11. {shotgate-0.2.0 → shotgate-0.2.2}/SECURITY.md +1 -1
  12. {shotgate-0.2.0 → shotgate-0.2.2}/docs/README.md +3 -3
  13. {shotgate-0.2.0 → shotgate-0.2.2}/docs/adr/0001-record-architecture-decisions.md +2 -2
  14. {shotgate-0.2.0 → shotgate-0.2.2}/docs/adr/0002-statistical-validation-core.md +3 -3
  15. shotgate-0.2.2/docs/adr/0004-rename-qforge-to-shotgate.md +35 -0
  16. shotgate-0.2.2/docs/adr/0005-license-apache-2-0.md +48 -0
  17. shotgate-0.2.2/docs/adr/0006-hardware-oracle-policy.md +48 -0
  18. {shotgate-0.2.0 → shotgate-0.2.2}/docs/architecture.md +14 -12
  19. {shotgate-0.2.0 → shotgate-0.2.2}/docs/assertions.md +14 -11
  20. {shotgate-0.2.0 → shotgate-0.2.2}/docs/diagrams/architecture.mmd +4 -4
  21. {shotgate-0.2.0 → shotgate-0.2.2}/docs/diagrams/pipeline.mmd +1 -1
  22. {shotgate-0.2.0 → shotgate-0.2.2}/docs/hardware-validation.md +50 -18
  23. {shotgate-0.2.0 → shotgate-0.2.2}/docs/motivation.md +12 -12
  24. {shotgate-0.2.0 → shotgate-0.2.2}/docs/pipeline.md +4 -4
  25. {shotgate-0.2.0 → shotgate-0.2.2}/docs/workflow-spec.md +8 -8
  26. shotgate-0.2.2/examples/bell-state/bell.qasm +8 -0
  27. {shotgate-0.2.0 → shotgate-0.2.2}/examples/bell-state/workflow.yaml +1 -1
  28. {shotgate-0.2.0 → shotgate-0.2.2}/examples/bell-state-hardware/workflow.yaml +2 -2
  29. shotgate-0.2.2/examples/bell-state-hardware-oracle-coverage/workflow.yaml +54 -0
  30. {shotgate-0.2.0 → shotgate-0.2.2}/infra/qemu/README.md +2 -2
  31. {shotgate-0.2.0 → shotgate-0.2.2}/infra/qemu/cloud-init/user-data +1 -1
  32. {shotgate-0.2.0 → shotgate-0.2.2}/infra/qemu/create-runner-vm.sh +3 -3
  33. {shotgate-0.2.0 → shotgate-0.2.2}/infra/terraform/README.md +7 -5
  34. {shotgate-0.2.0 → shotgate-0.2.2}/infra/terraform/examples/basic/main.tf +1 -1
  35. {shotgate-0.2.0 → shotgate-0.2.2}/infra/terraform/main.tf +2 -2
  36. {shotgate-0.2.0 → shotgate-0.2.2}/pyproject.toml +2 -2
  37. {shotgate-0.2.0 → shotgate-0.2.2}/scripts/demo.sh +2 -2
  38. {shotgate-0.2.0 → shotgate-0.2.2}/src/shotgate/__init__.py +1 -1
  39. {shotgate-0.2.0 → shotgate-0.2.2}/src/shotgate/backends/base.py +1 -1
  40. {shotgate-0.2.0 → shotgate-0.2.2}/src/shotgate/backends/ibm_runtime.py +16 -1
  41. {shotgate-0.2.0 → shotgate-0.2.2}/src/shotgate/config.py +2 -2
  42. {shotgate-0.2.0 → shotgate-0.2.2}/src/shotgate/report.py +3 -3
  43. {shotgate-0.2.0 → shotgate-0.2.2}/src/shotgate/telemetry.py +2 -2
  44. {shotgate-0.2.0 → shotgate-0.2.2}/src/shotgate/validation/metrics.py +1 -1
  45. {shotgate-0.2.0 → shotgate-0.2.2}/tests/test_ibm_backend.py +3 -3
  46. {shotgate-0.2.0 → shotgate-0.2.2}/.containerignore +0 -0
  47. {shotgate-0.2.0 → shotgate-0.2.2}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  48. {shotgate-0.2.0 → shotgate-0.2.2}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  49. {shotgate-0.2.0 → shotgate-0.2.2}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  50. {shotgate-0.2.0 → shotgate-0.2.2}/.github/dependabot.yml +0 -0
  51. {shotgate-0.2.0 → shotgate-0.2.2}/.github/scripts/pin-device.py +0 -0
  52. {shotgate-0.2.0 → shotgate-0.2.2}/.github/scripts/pull-base-image.sh +0 -0
  53. {shotgate-0.2.0 → shotgate-0.2.2}/.github/workflows/ci.yml +0 -0
  54. {shotgate-0.2.0 → shotgate-0.2.2}/.gitignore +0 -0
  55. {shotgate-0.2.0 → shotgate-0.2.2}/.gitlab-ci.yml +0 -0
  56. {shotgate-0.2.0 → shotgate-0.2.2}/CODEOWNERS +0 -0
  57. {shotgate-0.2.0 → shotgate-0.2.2}/CODE_OF_CONDUCT.md +0 -0
  58. {shotgate-0.2.0 → shotgate-0.2.2}/GOVERNANCE.md +0 -0
  59. {shotgate-0.2.0 → shotgate-0.2.2}/Jenkinsfile +0 -0
  60. {shotgate-0.2.0 → shotgate-0.2.2}/LICENSE +0 -0
  61. {shotgate-0.2.0 → shotgate-0.2.2}/MAINTAINERS.md +0 -0
  62. {shotgate-0.2.0 → shotgate-0.2.2}/NOTICE +0 -0
  63. {shotgate-0.2.0 → shotgate-0.2.2}/docs/adr/0003-container-and-vm-isolation.md +0 -0
  64. {shotgate-0.2.0 → shotgate-0.2.2}/docs/assets/bell-state-demo.svg +0 -0
  65. {shotgate-0.2.0 → shotgate-0.2.2}/docs/assets/shotgate-logomark.svg +0 -0
  66. {shotgate-0.2.0 → shotgate-0.2.2}/docs/getting-started.md +0 -0
  67. {shotgate-0.2.0/examples/bell-state → shotgate-0.2.2/examples/bell-state-hardware}/bell.qasm +0 -0
  68. {shotgate-0.2.0/examples/bell-state-hardware → shotgate-0.2.2/examples/bell-state-hardware-oracle-coverage}/bell.qasm +0 -0
  69. {shotgate-0.2.0 → shotgate-0.2.2}/examples/ghz-state/ghz.qasm +0 -0
  70. {shotgate-0.2.0 → shotgate-0.2.2}/examples/ghz-state/workflow.yaml +0 -0
  71. {shotgate-0.2.0 → shotgate-0.2.2}/examples/ghz-state-hardware/ghz.qasm +0 -0
  72. {shotgate-0.2.0 → shotgate-0.2.2}/examples/ghz-state-hardware/workflow.yaml +0 -0
  73. {shotgate-0.2.0 → shotgate-0.2.2}/examples/grover-2q/grover.qasm +0 -0
  74. {shotgate-0.2.0 → shotgate-0.2.2}/examples/grover-2q/workflow.yaml +0 -0
  75. {shotgate-0.2.0 → shotgate-0.2.2}/examples/grover-2q-hardware/grover.qasm +0 -0
  76. {shotgate-0.2.0 → shotgate-0.2.2}/examples/grover-2q-hardware/workflow.yaml +0 -0
  77. {shotgate-0.2.0 → shotgate-0.2.2}/infra/qemu/cloud-init/meta-data +0 -0
  78. {shotgate-0.2.0 → shotgate-0.2.2}/infra/terraform/outputs.tf +0 -0
  79. {shotgate-0.2.0 → shotgate-0.2.2}/infra/terraform/variables.tf +0 -0
  80. {shotgate-0.2.0 → shotgate-0.2.2}/infra/terraform/versions.tf +0 -0
  81. {shotgate-0.2.0 → shotgate-0.2.2}/src/shotgate/__main__.py +0 -0
  82. {shotgate-0.2.0 → shotgate-0.2.2}/src/shotgate/backends/__init__.py +0 -0
  83. {shotgate-0.2.0 → shotgate-0.2.2}/src/shotgate/backends/local_aer.py +0 -0
  84. {shotgate-0.2.0 → shotgate-0.2.2}/src/shotgate/backends/registry.py +0 -0
  85. {shotgate-0.2.0 → shotgate-0.2.2}/src/shotgate/circuits/__init__.py +0 -0
  86. {shotgate-0.2.0 → shotgate-0.2.2}/src/shotgate/circuits/loader.py +0 -0
  87. {shotgate-0.2.0 → shotgate-0.2.2}/src/shotgate/cli.py +0 -0
  88. {shotgate-0.2.0 → shotgate-0.2.2}/src/shotgate/pytest_plugin.py +0 -0
  89. {shotgate-0.2.0 → shotgate-0.2.2}/src/shotgate/runner.py +0 -0
  90. {shotgate-0.2.0 → shotgate-0.2.2}/src/shotgate/validation/__init__.py +0 -0
  91. {shotgate-0.2.0 → shotgate-0.2.2}/src/shotgate/validation/assertions.py +0 -0
  92. {shotgate-0.2.0 → shotgate-0.2.2}/tests/conftest.py +0 -0
  93. {shotgate-0.2.0 → shotgate-0.2.2}/tests/test_assertions.py +0 -0
  94. {shotgate-0.2.0 → shotgate-0.2.2}/tests/test_config.py +0 -0
  95. {shotgate-0.2.0 → shotgate-0.2.2}/tests/test_metrics.py +0 -0
  96. {shotgate-0.2.0 → shotgate-0.2.2}/tests/test_pytest_plugin.py +0 -0
  97. {shotgate-0.2.0 → shotgate-0.2.2}/tests/test_report.py +0 -0
  98. {shotgate-0.2.0 → shotgate-0.2.2}/tests/test_runner_integration.py +0 -0
@@ -0,0 +1,91 @@
1
+ name: dockerhub-mirror
2
+
3
+ # Mirror an already-published GHCR image set to Docker Hub, then sync this repo's
4
+ # README and tagline onto the Docker Hub repository page so the listing matches the
5
+ # source. GHCR stays the canonical registry; Docker Hub is a convenience mirror for
6
+ # discovery and the familiar `docker pull`. Runs on release (via workflow_call from
7
+ # release.yml) and on demand (workflow_dispatch) to re-mirror or back-fill any version.
8
+ #
9
+ # Credentials live in the `dockerhub` environment: DOCKERHUB_USERNAME and
10
+ # DOCKERHUB_TOKEN (a Docker Hub access token), and optionally DOCKERHUB_NAMESPACE
11
+ # to push under a Hub organization instead of the username. Absent credentials
12
+ # (a fork), the mirror step is skipped rather than failing.
13
+ #
14
+ # The README sync uses peter-evans/dockerhub-description, which drives the Docker
15
+ # Hub HTTP API. That API accepts a personal access token only if it is scoped
16
+ # read/write/delete; if DOCKERHUB_TOKEN is scoped narrower, set
17
+ # DOCKERHUB_DESCRIPTION_PASSWORD in the `dockerhub` environment (the account
18
+ # password or a read/write/delete token) and it is used in preference. The sync
19
+ # step is non-fatal (`continue-on-error`): a description failure never blocks the
20
+ # image mirror or the release.
21
+
22
+ on:
23
+ workflow_dispatch:
24
+ inputs:
25
+ version:
26
+ description: "Version to mirror from GHCR to Docker Hub (e.g. 0.2.1)"
27
+ required: true
28
+ workflow_call:
29
+ inputs:
30
+ version:
31
+ required: true
32
+ type: string
33
+
34
+ permissions:
35
+ contents: read
36
+ packages: read
37
+
38
+ jobs:
39
+ mirror:
40
+ name: mirror GHCR -> Docker Hub
41
+ runs-on: ubuntu-latest
42
+ environment: dockerhub
43
+ env:
44
+ DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
45
+ DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }}
46
+ DOCKERHUB_NAMESPACE: ${{ secrets.DOCKERHUB_NAMESPACE }}
47
+ steps:
48
+ - uses: actions/checkout@v6
49
+
50
+ - name: Compute Docker Hub repository
51
+ id: hub
52
+ if: ${{ env.DOCKERHUB_USERNAME != '' && env.DOCKERHUB_TOKEN != '' }}
53
+ run: |
54
+ # Namespace defaults to the Hub username; DOCKERHUB_NAMESPACE overrides
55
+ # it to push under a Hub organization. Same rule as the mirror step.
56
+ NS="${DOCKERHUB_NAMESPACE:-$DOCKERHUB_USERNAME}"
57
+ echo "repository=${NS,,}/shotgate" >> "$GITHUB_OUTPUT"
58
+
59
+ - name: Mirror the version, latest, and -ibm tags
60
+ if: ${{ env.DOCKERHUB_USERNAME != '' && env.DOCKERHUB_TOKEN != '' }}
61
+ env:
62
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
63
+ ACTOR: ${{ github.actor }}
64
+ REPO: ${{ github.repository }}
65
+ VERSION: ${{ inputs.version }}
66
+ HUB_REPO: ${{ steps.hub.outputs.repository }}
67
+ run: |
68
+ V="${VERSION#v}" # tolerate a leading 'v'
69
+ GHCR="ghcr.io/${REPO,,}"
70
+ DH="docker.io/${HUB_REPO}"
71
+ echo "$GH_TOKEN" | podman login ghcr.io -u "$ACTOR" --password-stdin
72
+ echo "$DOCKERHUB_TOKEN" | podman login docker.io -u "$DOCKERHUB_USERNAME" --password-stdin
73
+ for tag in "$V" latest "${V}-ibm" latest-ibm; do
74
+ podman pull "${GHCR}:${tag}"
75
+ podman tag "${GHCR}:${tag}" "${DH}:${tag}"
76
+ podman push "${DH}:${tag}"
77
+ done
78
+ echo "Mirrored ${GHCR}:{${V},latest,${V}-ibm,latest-ibm} -> ${DH}"
79
+
80
+ # Keep the Docker Hub repository page in sync with the source: the repo
81
+ # README becomes the full description, the project tagline the short one.
82
+ - name: Sync Docker Hub README and short description
83
+ if: ${{ env.DOCKERHUB_USERNAME != '' && env.DOCKERHUB_TOKEN != '' }}
84
+ continue-on-error: true
85
+ uses: peter-evans/dockerhub-description@v5
86
+ with:
87
+ username: ${{ secrets.DOCKERHUB_USERNAME }}
88
+ password: ${{ secrets.DOCKERHUB_DESCRIPTION_PASSWORD || secrets.DOCKERHUB_TOKEN }}
89
+ repository: ${{ steps.hub.outputs.repository }}
90
+ short-description: "Container-native CI/CD quality gates for quantum circuits"
91
+ readme-filepath: ./README.md
@@ -11,9 +11,9 @@ on:
11
11
  workflow_dispatch:
12
12
  inputs:
13
13
  device:
14
- description: "IBM device to pin (empty = least_busy)"
14
+ description: "IBM device to pin (empty = least_busy, the portable default)"
15
15
  required: false
16
- default: "ibm_fez"
16
+ default: ""
17
17
  shots:
18
18
  description: "Shots per job"
19
19
  required: false
@@ -73,6 +73,30 @@ jobs:
73
73
  exit "$fail"
74
74
  '
75
75
 
76
+ - name: Oracle-coverage diagnostic (non-gating, measures chi_square on QPU)
77
+ env:
78
+ SHOTGATE_IBM_TOKEN: ${{ secrets.SHOTGATE_IBM_TOKEN }}
79
+ DEVICE: ${{ inputs.device }}
80
+ SHOTS: ${{ inputs.shots }}
81
+ REQUESTED_VERSION: ${{ inputs.version }}
82
+ run: |
83
+ # Runs all five oracles on one Bell circuit so chi_square has a hardware
84
+ # data point. chi_square is EXPECTED to fail under device noise, so this
85
+ # step never fails the job (|| true); the JSON report carries the number.
86
+ podman run --rm \
87
+ -v "$PWD:/work:ro" -v "$PWD/reports:/reports" \
88
+ -e SHOTGATE_IBM_TOKEN -e DEVICE -e SHOTS -e REQUESTED_VERSION \
89
+ docker.io/library/python:3.12-slim bash -euc '
90
+ SPEC="shotgate[ibm]"
91
+ [ -n "$REQUESTED_VERSION" ] && SPEC="shotgate[ibm]==$REQUESTED_VERSION"
92
+ pip install -q --no-cache-dir "$SPEC"
93
+ wf=bell-state-hardware-oracle-coverage
94
+ cp -r "/work/examples/${wf}" "/tmp/${wf}" && cd "/tmp/${wf}"
95
+ python /work/.github/scripts/pin-device.py workflow.yaml "$DEVICE"
96
+ shotgate run workflow.yaml --shots "$SHOTS" \
97
+ --json "/reports/${wf}.json" --markdown "/reports/${wf}.md" || true
98
+ ' || true
99
+
76
100
  - name: Publish step summary
77
101
  if: always()
78
102
  run: |
@@ -40,7 +40,16 @@ jobs:
40
40
  docker.io/library/python:3.12-slim bash -euc '
41
41
  SPEC="shotgate[aer]"
42
42
  [ -n "$REQUESTED_VERSION" ] && SPEC="shotgate[aer]==$REQUESTED_VERSION"
43
- pip install -q --no-cache-dir "$SPEC" pytest
43
+ # A freshly released version can lag for several minutes in the PyPI
44
+ # /simple/ index that pip reads, even after the files are live and the
45
+ # per-release JSON shows them (observed ~10 min on 2026-06-11). Retry
46
+ # generously so dispatching right after a release tolerates the lag.
47
+ for attempt in $(seq 1 20); do
48
+ pip install -q --no-cache-dir "$SPEC" pytest && break
49
+ echo "install attempt ${attempt}/20 failed (index may be propagating); retrying in 45s" >&2
50
+ sleep 45
51
+ done
52
+ pip show shotgate >/dev/null # fail the step if all attempts failed
44
53
  echo "--- installed:"
45
54
  pip show shotgate | sed -n "1,2p"
46
55
  echo "--- CLI gate (exit 0 expected):"
@@ -98,6 +98,17 @@ jobs:
98
98
  podman push "${IMG}:${VERSION}-ibm"
99
99
  podman push "${IMG}:latest-ibm"
100
100
 
101
+ # Mirror the just-published GHCR images to Docker Hub (optional convenience
102
+ # registry). Delegated to the reusable dockerhub-mirror workflow, which is also
103
+ # dispatchable on its own to re-mirror any version. Skipped automatically when
104
+ # the dockerhub environment has no credentials.
105
+ mirror-dockerhub:
106
+ needs: publish-image
107
+ uses: ./.github/workflows/dockerhub-mirror.yml
108
+ with:
109
+ version: ${{ github.ref_name }}
110
+ secrets: inherit
111
+
101
112
  publish-pypi:
102
113
  name: publish to PyPI (trusted publishing)
103
114
  runs-on: ubuntu-latest
@@ -134,8 +145,38 @@ jobs:
134
145
  with:
135
146
  name: dist
136
147
  path: dist
148
+ - name: Compose install instructions
149
+ id: notes
150
+ run: |
151
+ V="${GITHUB_REF_NAME#v}"
152
+ {
153
+ echo "## Install ${GITHUB_REF_NAME}"
154
+ echo
155
+ echo "The package is on **PyPI** and the image on the **GitHub Container Registry (GHCR)** for convenience (the usual one-liners below). If you would rather not use a package index at all, the wheel attached to this release and the GHCR image are both pullable straight from GitHub, no extra account needed."
156
+ echo
157
+ echo "**Python package** (PyPI, or the attached wheel):"
158
+ echo '```bash'
159
+ echo "pip install 'shotgate[aer]==${V}'"
160
+ echo "# or straight from this release, no index:"
161
+ echo "pip install https://github.com/${GITHUB_REPOSITORY}/releases/download/${GITHUB_REF_NAME}/shotgate-${V}-py3-none-any.whl"
162
+ echo '```'
163
+ echo
164
+ echo "**Container** (GHCR, canonical; add the \`-ibm\` tag suffix for the QPU-capable variant):"
165
+ echo '```bash'
166
+ echo "podman pull ghcr.io/${GITHUB_REPOSITORY}:${V}"
167
+ echo "podman run --rm -v \"\$PWD:/work:Z\" -w /work ghcr.io/${GITHUB_REPOSITORY}:${V} run examples/bell-state/workflow.yaml"
168
+ echo "# also mirrored to Docker Hub: docker.io/${GITHUB_REPOSITORY}:${V}"
169
+ echo '```'
170
+ echo
171
+ echo "---"
172
+ } > release-notes.md
173
+ env:
174
+ GITHUB_REPOSITORY: ${{ github.repository }}
175
+
137
176
  - name: Create release
138
177
  uses: softprops/action-gh-release@v3
139
178
  with:
140
179
  files: dist/*
180
+ body_path: release-notes.md
181
+ append_body: true
141
182
  generate_release_notes: true
@@ -6,7 +6,57 @@ All notable changes to this project are documented here. The format is based on
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
- *Nothing yet.*
9
+ ## [0.2.2] - 2026-06-11
10
+
11
+ ### Added
12
+
13
+ - **Three Architecture Decision Records.** ADR-0004 (rename `qforge` to `shotgate`,
14
+ including the breaking `apiVersion` change), ADR-0005 (license MIT to
15
+ AGPL-3.0-or-later to Apache-2.0, and the DCO inbound policy), and ADR-0006
16
+ (`chi_square` simulator-only, noise-aware hardware thresholds), completing the
17
+ ADR series against the GOVERNANCE.md criteria.
18
+ - **Docker Hub repository page sync.** After mirroring images, the `dockerhub-mirror`
19
+ workflow now pushes the repository README and the project tagline to the Docker Hub
20
+ repository description, so the Hub listing tracks the source. The step is non-fatal:
21
+ a description-API failure never blocks the image mirror or the release.
22
+
23
+ ### Changed
24
+
25
+ - **Docker Hub mirroring is a reusable, dispatchable workflow.** The mirror moved from an
26
+ inline release job to `dockerhub-mirror.yml` (`workflow_call` from the release plus
27
+ `workflow_dispatch` to back-fill any version), with credentials read from the
28
+ `dockerhub` environment (`DOCKERHUB_USERNAME`, `DOCKERHUB_TOKEN`, optional
29
+ `DOCKERHUB_NAMESPACE`) instead of repository secrets.
30
+ - **Reporter copy uses ASCII separators.** The Markdown summary title format is now
31
+ ``## shotgate: `name` (status)``, the no-assertion row prints `n/a`, and the plain
32
+ console fallback separates label and message with a colon; previously all three used
33
+ an em-dash. JUnit and JSON payloads are unchanged.
34
+
35
+ ## [0.2.1] - 2026-06-11
36
+
37
+ ### Added
38
+
39
+ - **Full oracle coverage on hardware.** A non-gating diagnostic example,
40
+ `bell-state-hardware-oracle-coverage`, runs all five oracles on one Bell circuit so
41
+ `chi_square` also has a real-QPU data point. Measured on `ibm_fez`: the four
42
+ distance/structural oracles passed while `chi_square` returned p-value 0.0000
43
+ (statistic 1.5e17, dof 3), confirming why it is simulator-only. Mechanism and numbers
44
+ in `docs/hardware-validation.md` section 9.
45
+ - **GitHub-only install path in release notes.** Each release now documents installing the
46
+ attached wheel and pulling the GHCR image directly, so neither PyPI nor Docker Hub is
47
+ required to consume a release.
48
+ - **Optional Docker Hub mirror** in the release pipeline. When the `DOCKERHUB_USERNAME` and
49
+ `DOCKERHUB_TOKEN` repository secrets are present, released images are mirrored to Docker
50
+ Hub alongside the canonical GHCR images; absent the secrets the step is skipped and the
51
+ release is unaffected.
52
+
53
+ ### Changed
54
+
55
+ - **Portable device selection.** A pinned `ibm` device that the account or instance cannot
56
+ reach now raises a clear error listing the reachable real devices and pointing at the
57
+ `least_busy` default, instead of an opaque Qiskit lookup failure. The
58
+ `hardware-validation` workflow's device input now defaults to empty (`least_busy`) rather
59
+ than a pinned `ibm_fez`.
10
60
 
11
61
  ## [0.2.0] - 2026-06-11
12
62
 
@@ -76,7 +126,7 @@ All notable changes to this project are documented here. The format is based on
76
126
  moved to the new name. The canonical home is `github.com/coldqubit/shotgate` and the
77
127
  published image is `ghcr.io/coldqubit/shotgate`.
78
128
  - **Pull-first usage.** Documentation now leads with `podman run
79
- ghcr.io/coldqubit/shotgate …`; building from source is the contributor fallback.
129
+ ghcr.io/coldqubit/shotgate ...`; building from source is the contributor fallback.
80
130
  - **Honest extras.** `braket` and `mitigation` are marked *planned* and removed from the
81
131
  installable `all` extra, since no Braket backend or Mitiq integration ships yet.
82
132
  `--backend braket` now fails fast at schema validation with a clear message.
@@ -97,7 +147,7 @@ All notable changes to this project are documented here. The format is based on
97
147
  - **Hardened IBM/QPU backend**: robust counts extraction from named classical registers
98
148
  (with a clear error on unexpected result shapes), corrected Runtime channel default,
99
149
  a token-gated smoke test, and an `[ibm]`-baked image variant (build arg
100
- `SHOTGATE_EXTRAS="aer,ibm"`, published as the `:…-ibm` image tag).
150
+ `SHOTGATE_EXTRAS="aer,ibm"`, published as the `:...-ibm` image tag).
101
151
  - **Noise-tolerant example** (`examples/bell-state-hardware/`) with relaxed thresholds
102
152
  for real-device runs, plus a documented simulator-vs-QPU threshold split.
103
153
  - **`docs/hardware-validation.md`**: a step-by-step plan and acceptance matrix for
@@ -143,7 +193,9 @@ All notable changes to this project are documented here. The format is based on
143
193
  (with the math), getting-started guide, and ADRs.
144
194
  - **Examples**: Bell state, 3-qubit GHZ, and 2-qubit Grover workflows.
145
195
 
146
- [Unreleased]: https://github.com/coldqubit/shotgate/compare/v0.2.0...HEAD
196
+ [Unreleased]: https://github.com/coldqubit/shotgate/compare/v0.2.2...HEAD
197
+ [0.2.2]: https://github.com/coldqubit/shotgate/compare/v0.2.1...v0.2.2
198
+ [0.2.1]: https://github.com/coldqubit/shotgate/compare/v0.2.0...v0.2.1
147
199
  [0.2.0]: https://github.com/coldqubit/shotgate/compare/v0.1.1...v0.2.0
148
200
  [0.1.1]: https://github.com/coldqubit/shotgate/compare/v0.1.0...v0.1.1
149
201
  [0.1.0]: https://github.com/coldqubit/shotgate/releases/tag/v0.1.0
@@ -7,11 +7,11 @@ favors small, well-tested, well-reasoned changes.
7
7
 
8
8
  - Be kind; follow the [Code of Conduct](CODE_OF_CONDUCT.md).
9
9
  - Discuss non-trivial changes in an issue first (especially new assertion oracles or
10
- backends they have design implications).
10
+ backends, which have design implications).
11
11
  - Keep the **validation core dependency-free** (standard library + pydantic). Quantum
12
12
  SDKs are optional extras, imported lazily inside backends only.
13
13
 
14
- ## Development workflow (containers only no host installs)
14
+ ## Development workflow (containers only, no host installs)
15
15
 
16
16
  Everything runs through Podman via the `Makefile`:
17
17
 
@@ -1,4 +1,4 @@
1
- # shotgate runtime image built and run with Podman (rootless-friendly).
1
+ # shotgate runtime image, built and run with Podman (rootless-friendly).
2
2
  #
3
3
  # Multi-stage:
4
4
  # builder -> installs shotgate + the Aer simulator into an isolated venv
@@ -1,4 +1,4 @@
1
- # shotgate Podman/QEMU task runner.
1
+ # shotgate: Podman/QEMU task runner.
2
2
  #
3
3
  # Everything runs in containers or VMs; nothing is installed on the host.
4
4
  # Override any variable on the command line, e.g. make run WORKFLOW=examples/ghz-state/workflow.yaml
@@ -14,7 +14,7 @@ MOUNT := -v "$(CURDIR):/work:Z" -w /work
14
14
  RUN := $(PODMAN) run --rm $(MOUNT)
15
15
 
16
16
  # Map the invoking host user through the container's user namespace so that
17
- # report files written to the bind mount are owned by you while the image
17
+ # report files written to the bind mount are owned by you, while the image
18
18
  # keeps its non-root default user. The standard Podman idiom for this case.
19
19
  USERMAP := --userns=keep-id --user $(shell id -u):$(shell id -g)
20
20
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: shotgate
3
- Version: 0.2.0
3
+ Version: 0.2.2
4
4
  Summary: Container-native CI/CD quality gates for quantum circuits: statistically validate probabilistic output across simulators and QPUs.
5
5
  Project-URL: Homepage, https://github.com/coldqubit/shotgate
6
6
  Project-URL: Documentation, https://github.com/coldqubit/shotgate/tree/main/docs
@@ -138,7 +138,7 @@ $ shotgate run examples/bell-state/workflow.yaml
138
138
  The same run drops into a pipeline through the Markdown reporter (`--markdown`), rendered
139
139
  as a step summary or a PR comment:
140
140
 
141
- > ## shotgate: `bell-state` ✅ passed
141
+ > ## shotgate: `bell-state` (✅ passed)
142
142
  >
143
143
  > - Jobs: **1**, failed: **0**
144
144
  > - Assertions: **5**, failed: **0**
@@ -180,6 +180,10 @@ podman run --rm -e SHOTGATE_IBM_TOKEN \
180
180
  run examples/bell-state-hardware/workflow.yaml --backend ibm
181
181
  ```
182
182
 
183
+ The same images are mirrored to Docker Hub if you prefer it: swap the registry prefix for
184
+ `docker.io/coldqubit/shotgate` (tags `latest`, `latest-ibm`, and each version). GHCR is the
185
+ canonical registry; the Docker Hub copy is a convenience mirror.
186
+
183
187
  ### Path B: pip (CLI and pytest plugin)
184
188
 
185
189
  Install the package with the backend extra you need (`aer` for the local simulator, `ibm` for
@@ -91,7 +91,7 @@ $ shotgate run examples/bell-state/workflow.yaml
91
91
  The same run drops into a pipeline through the Markdown reporter (`--markdown`), rendered
92
92
  as a step summary or a PR comment:
93
93
 
94
- > ## shotgate: `bell-state` ✅ passed
94
+ > ## shotgate: `bell-state` (✅ passed)
95
95
  >
96
96
  > - Jobs: **1**, failed: **0**
97
97
  > - Assertions: **5**, failed: **0**
@@ -133,6 +133,10 @@ podman run --rm -e SHOTGATE_IBM_TOKEN \
133
133
  run examples/bell-state-hardware/workflow.yaml --backend ibm
134
134
  ```
135
135
 
136
+ The same images are mirrored to Docker Hub if you prefer it: swap the registry prefix for
137
+ `docker.io/coldqubit/shotgate` (tags `latest`, `latest-ibm`, and each version). GHCR is the
138
+ canonical registry; the Docker Hub copy is a convenience mirror.
139
+
136
140
  ### Path B: pip (CLI and pytest plugin)
137
141
 
138
142
  Install the package with the backend extra you need (`aer` for the local simulator, `ibm` for
@@ -15,7 +15,7 @@ acknowledge within 72 hours and to provide a remediation timeline after triage.
15
15
 
16
16
  ## Security model (what to attack / what we defend)
17
17
 
18
- - **Untrusted circuits.** Circuits are OpenQASM parsed by qiskit's QASM reader not
18
+ - **Untrusted circuits.** Circuits are OpenQASM parsed by qiskit's QASM reader, not
19
19
  `eval`'d Python. For circuits from untrusted sources, use the **VM isolation tier**
20
20
  (`infra/qemu`), which runs the workflow in an ephemeral KVM micro-VM.
21
21
  - **Secrets.** Provider tokens are read from environment variables / container `-e`
@@ -7,12 +7,12 @@
7
7
  | [Pipeline Schema](pipeline.md) | How shotgate gates a CI/CD pipeline; stage contract; exit codes. |
8
8
  | [Workflow Specification](workflow-spec.md) | The `shotgate.dev/v1alpha1` YAML schema, field by field. |
9
9
  | [Assertion Catalog](assertions.md) | The statistical oracles, with the math and threshold guidance. |
10
- | [Hardware Validation Plan](hardware-validation.md) | v0.2 runbook to validate the gates on a real IBM QPU. |
10
+ | [Hardware Validation Plan](hardware-validation.md) | v0.2 milestone: runbook and measured `ibm_fez` baseline (2026-06-11). |
11
11
  | [Motivation](motivation.md) | The market/community gap shotgate fills, with sources. |
12
12
  | [ADRs](adr/) | Architecture Decision Records and their rationale. |
13
13
  | [Diagrams](diagrams/) | Mermaid sources for the architecture and pipeline diagrams. |
14
14
 
15
15
  Infrastructure docs live next to the code they describe:
16
16
 
17
- - [Terraform module](../infra/terraform/README.md) quantum workflow as code.
18
- - [KVM/QEMU runner](../infra/qemu/README.md) ephemeral VM isolation tier.
17
+ - [Terraform module](../infra/terraform/README.md): quantum workflow as code.
18
+ - [KVM/QEMU runner](../infra/qemu/README.md): ephemeral VM isolation tier.
@@ -6,8 +6,8 @@
6
6
  ## Context
7
7
 
8
8
  shotgate sits at an immature intersection (quantum × DevOps) where the "right" design
9
- is not yet settled by convention. Decisions why statistical oracles, why containers,
10
- why a Terraform module instead of a provider need to be legible to contributors and
9
+ is not yet settled by convention. Decisions (why statistical oracles, why containers,
10
+ why a Terraform module instead of a provider) need to be legible to contributors and
11
11
  to our future selves.
12
12
 
13
13
  ## Decision
@@ -7,10 +7,10 @@
7
7
 
8
8
  Quantum programs are probabilistic; exact-equality assertions are either flaky or
9
9
  vacuous. The academic literature (χ²-as-oracle, QUTest, QuCheck, QUT) establishes the
10
- correct techniques total variation distance, Hellinger fidelity, chi-square
11
- goodness-of-fit but they live in research prototypes, not in production CI tooling.
10
+ correct techniques (total variation distance, Hellinger fidelity, chi-square
11
+ goodness-of-fit), but they live in research prototypes, not in production CI tooling.
12
12
  Meanwhile DevOps writers repeatedly note that quantum CI "lacks robust test
13
- frameworks" and needs "specialized validation in CI/CD pipelines".
13
+ frameworks" and needs "specialized validation... in CI/CD pipelines".
14
14
 
15
15
  We must also decide the dependency footprint. Pulling SciPy (for `chi2.sf`) and numpy
16
16
  into the core would make the metrics layer heavy and couple it to a scientific stack.
@@ -0,0 +1,35 @@
1
+ # ADR-0004: Rename qforge to shotgate (and the workflow apiVersion with it)
2
+
3
+ - **Status:** Accepted
4
+ - **Date:** 2026-06-01
5
+
6
+ ## Context
7
+
8
+ The project started on 2026-06-01 under the name `qforge`. Before any release was
9
+ tagged, two problems surfaced: the name was already taken on the package indexes
10
+ (PyPI and crates.io), and it raised a trademark concern on the VS Code marketplace.
11
+ The name is load-bearing in more places than the repository title: the Python
12
+ package, the command-line interface (CLI) program, the container image path, the
13
+ environment variables, and the workflow schema's `apiVersion` literal
14
+ (`qforge.dev/v1alpha1`) all embed it.
15
+
16
+ ## Decision
17
+
18
+ Rename the project to **shotgate** everywhere the old name appeared: package
19
+ `src/shotgate`, CLI program `shotgate`, image `ghcr.io/coldqubit/shotgate`,
20
+ environment variable prefix `SHOTGATE_*`, and the workflow schema pin
21
+ `apiVersion: shotgate.dev/v1alpha1`. The schema pin is a pydantic `Literal`, so a
22
+ workflow declaring the old `qforge.dev/v1alpha1` fails schema validation rather
23
+ than being silently accepted.
24
+
25
+ ## Consequences
26
+
27
+ - **+** The name is unique on PyPI and the container registries, so the package and
28
+ image are installable under their own name with no squatting or trademark risk.
29
+ - **+** It describes the product (gating on measurement shots) instead of a generic
30
+ "forge" metaphor.
31
+ - **−** The `apiVersion` change is breaking for any pre-rename workflow file. The
32
+ impact was zero in practice: the rename landed on 2026-06-01 and the first tagged
33
+ release (`v0.1.0`) followed on 2026-06-10, so no published package, image, or tag
34
+ ever carried the old name and no external consumer existed to break.
35
+ - The old name survives only in git history and in the `CHANGELOG.md` v0.1.0 notes.
@@ -0,0 +1,48 @@
1
+ # ADR-0005: License is Apache-2.0 (after MIT and an AGPL interlude)
2
+
3
+ - **Status:** Accepted
4
+ - **Date:** 2026-06-08
5
+
6
+ ## Context
7
+
8
+ The project's license changed twice before the first release settled it:
9
+
10
+ 1. **MIT** at inception (2026-06-01).
11
+ 2. **AGPL-3.0-or-later** later the same day, chosen for the network copyleft:
12
+ distributing the tool, or running a modified version as a hosted service, would
13
+ have required releasing source.
14
+ 3. **Apache-2.0** on 2026-06-08, two days before the first tagged release.
15
+
16
+ The week under AGPL exposed a conflict with the adoption model. shotgate's target
17
+ user is a corporate continuous integration (CI) pipeline, and the quantum ecosystem
18
+ it builds on (Qiskit, Qiskit Aer, Cirq, Mitiq) is Apache-2.0 licensed; a
19
+ network-copyleft gate inside that stack invites legal review friction that a CI
20
+ utility cannot justify, and the "hosted modified service" trigger is ambiguous for a
21
+ tool whose whole purpose is to run inside other people's pipelines.
22
+
23
+ Relicensing was legally clean at that date: every line of source had a single
24
+ copyright holder (the maintainer), since the only third-party commits were
25
+ Dependabot version-range bumps and none had landed before the relicense commit.
26
+
27
+ ## Decision
28
+
29
+ License the project **Apache-2.0**: verbatim license text in `LICENSE`, the
30
+ two-line SPDX header (`Apache-2.0`, `Copyright (C) 2026 coldqubit`) in all `src/`
31
+ files (17 files at the time), the `Apache-2.0` expression and classifier in
32
+ `pyproject.toml`, and the OCI license label in the `Containerfile`. Inbound
33
+ contributions are accepted under a Developer Certificate of Origin (DCO) sign-off
34
+ carrying the same Apache-2.0 terms (Apache-2.0 section 5), with no separate
35
+ contributor license agreement.
36
+
37
+ ## Consequences
38
+
39
+ - **+** Permissive adoption: use, modification, and redistribution for any purpose,
40
+ including commercial and closed-source, retaining the license and attribution
41
+ notices (Apache-2.0 sections 4(a) through 4(d)).
42
+ - **+** An explicit patent grant (section 3), which MIT lacked.
43
+ - **+** License-compatible with the Apache-2.0 quantum SDK stack it imports.
44
+ - **−** The AGPL network-copyleft promise is removed, not replaced: a vendor can
45
+ ship a modified closed-source shotgate as a service.
46
+ - **−** Practically irreversible: once external DCO-signed contributions land,
47
+ relicensing again would require every contributor's consent. This ADR therefore
48
+ also fixes the inbound policy (DCO, same license in and out).
@@ -0,0 +1,48 @@
1
+ # ADR-0006: chi_square is simulator-only; hardware gates use distance, fidelity, and structural oracles
2
+
3
+ - **Status:** Accepted
4
+ - **Date:** 2026-06-11
5
+
6
+ ## Context
7
+
8
+ The v0.2 milestone ran the example gates on a real quantum processing unit (QPU)
9
+ for the first time (`ibm_fez`, 156-qubit Heron r2, 4096 shots per job). Two facts
10
+ came out of those runs:
11
+
12
+ 1. Simulator-tight thresholds (total variation distance (TVD) ≤ 0.03, Hellinger
13
+ fidelity ≥ 0.99, leakage ≤ 0.005) fail on a healthy device: the measured Bell
14
+ TVD was 0.1284 and the GHZ-3 TVD 0.1536.
15
+ 2. `chi_square` fails on hardware for a mechanical reason, not a tuning one. The
16
+ non-gating diagnostic Bell job (`d8l592rqv2lc738621eg`) returned statistic
17
+ 1.5e17, dof 3, p-value 0.0000, while the four distance/structural oracles passed
18
+ on the same counts (TVD 0.1350, fidelity 0.8650, leakage 0.1350, P(`00`) 0.4343).
19
+ The ideal expected distribution `{00: 0.5, 11: 0.5}` assigns probability 0 to
20
+ the error states `01`/`10`; the implementation floors expected counts at
21
+ `_MIN_EXPECTED = 1e-12` to keep the statistic finite, so each of the 553 leaked
22
+ shots contributes on the order of `observed^2 / 1e-12`. Against an ideal support,
23
+ any device leakage forces rejection regardless of thresholds.
24
+
25
+ ## Decision
26
+
27
+ 1. **Hardware gates use the distance, fidelity, marginal, and structural oracles**
28
+ (`distribution_tvd`, `hellinger_fidelity`, `state_probability`,
29
+ `allowed_states`) with noise-aware thresholds (Bell: TVD ≤ 0.15, fidelity
30
+ ≥ 0.85, leakage ≤ 0.15; full table in `docs/hardware-validation.md` section 4),
31
+ encoded in the `examples/*-hardware` workflows.
32
+ 2. **`chi_square` stays simulator-only** until a gate can declare a noise-aware
33
+ expected distribution (a device error model with nonzero mass on the error
34
+ states), which is out of scope for v0.2.
35
+ 3. A **non-gating oracle-coverage diagnostic**
36
+ (`examples/bell-state-hardware-oracle-coverage`) keeps measuring all five
37
+ oracles on hardware so the exclusion stays evidence-based run over run.
38
+
39
+ ## Consequences
40
+
41
+ - **+** The hardware gates pass a healthy device with measured margins of 0.0216
42
+ (Bell TVD, the tightest) to 0.1357 (Grover P(`11`)) while still bounding leakage
43
+ and fidelity, so they catch a broken circuit or mis-mapped qubits.
44
+ - **−** The formal hypothesis test is unavailable on hardware, so hardware gating
45
+ loses the goodness-of-fit (GoF) guarantee and relies on distance bounds instead.
46
+ - Revisit when an error-model expected distribution exists (candidate for the v0.3
47
+ error-mitigation work); the diagnostic's measurements will show when `chi_square`
48
+ becomes viable on devices.