diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..a2db656 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +* @m2papierz diff --git a/.github/ISSUE_TEMPLATES/bug_report.yaml b/.github/ISSUE_TEMPLATES/bug_report.yaml new file mode 100644 index 0000000..4e5eed5 --- /dev/null +++ b/.github/ISSUE_TEMPLATES/bug_report.yaml @@ -0,0 +1,48 @@ +name: Bug report +description: Report a reproducible bug in devqubit +labels: ["bug"] +body: + - type: textarea + id: what + attributes: + label: What happened? + description: Describe the bug clearly. + validations: + required: true + + - type: textarea + id: repro + attributes: + label: Steps to reproduce + description: Include a minimal snippet or CLI command. + placeholder: | + 1. ... + 2. ... + 3. ... + validations: + required: true + + - type: textarea + id: expected + attributes: + label: Expected behavior + validations: + required: true + + - type: input + id: version + attributes: + label: devqubit version + placeholder: e.g. 0.1.0 (or commit SHA) + validations: + required: true + + - type: textarea + id: env + attributes: + label: Environment + placeholder: | + OS: + Python: + SDK (Qiskit/Braket/Cirq/PennyLane/Other): + Backend (sim/hardware): diff --git a/.github/ISSUE_TEMPLATES/config.yml b/.github/ISSUE_TEMPLATES/config.yml new file mode 100644 index 0000000..aaeaba6 --- /dev/null +++ b/.github/ISSUE_TEMPLATES/config.yml @@ -0,0 +1,8 @@ +blank_issues_enabled: false +contact_links: + - name: Questions / Discussions + url: https://github.com/devqubit-labs/devqubit/discussions + about: Please ask questions here (Issues are for bugs and actionable requests). + - name: Security vulnerability report + url: https://github.com/devqubit-labs/devqubit/security/advisories/new + about: Please report security issues privately. diff --git a/.github/ISSUE_TEMPLATES/docs.yaml b/.github/ISSUE_TEMPLATES/docs.yaml new file mode 100644 index 0000000..59a84b6 --- /dev/null +++ b/.github/ISSUE_TEMPLATES/docs.yaml @@ -0,0 +1,10 @@ +name: Documentation +description: Report missing/unclear docs +labels: ["documentation"] +body: + - type: textarea + id: change + attributes: + label: What should be improved? + validations: + required: true diff --git a/.github/ISSUE_TEMPLATES/feature_request.yaml b/.github/ISSUE_TEMPLATES/feature_request.yaml new file mode 100644 index 0000000..8b466af --- /dev/null +++ b/.github/ISSUE_TEMPLATES/feature_request.yaml @@ -0,0 +1,25 @@ +name: Feature request +description: Suggest an improvement or new capability +labels: ["enhancement"] +body: + - type: textarea + id: problem + attributes: + label: Problem statement + description: What problem are you trying to solve? + validations: + required: true + + - type: textarea + id: proposal + attributes: + label: Proposed solution + description: What would you like devqubit to do? + validations: + required: true + + - type: textarea + id: context + attributes: + label: Context + description: SDK/backend setup, constraints, links to examples. diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..6b05233 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,11 @@ +version: 2 +updates: + - package-ecosystem: "uv" + directory: "/" + schedule: + interval: "weekly" + + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000..7459923 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,28 @@ +## Summary +What does this PR change, and why? + +## Type of change +- [ ] Bug fix +- [ ] New feature +- [ ] Refactor (no user-facing change) +- [ ] Docs only +- [ ] CI/build tooling +- [ ] Breaking change + +## Related issues / context +Link issues, discussions, or prior PRs: +- Closes # + +## Changelog (user-facing only) +- [ ] I added a towncrier fragment in `changelog.d/` (skip for internal-only changes) + +## Checklist +- [ ] I ran lint locally (`uv run pre-commit run --all-files`) +- [ ] I ran tests locally (`uv run pytest`) +- [ ] I added/updated tests for behavior changes +- [ ] I updated docs/README/examples if needed +- [ ] If I changed dependencies, I updated `uv.lock` (`uv lock`) and committed it +- [ ] I considered backward compatibility and security impact + +## Notes for reviewers +Anything tricky, non-obvious, or follow-up work? diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1175149..cd6d35a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -4,6 +4,7 @@ Thanks for your interest in contributing to **devqubit**! This guide keeps contr - Please follow our community rules in **CODE_OF_CONDUCT.md**. - For security issues, **do not** open a public issue (see [Security](#security)). +- Questions / support: prefer **GitHub Discussions** (Issues are for actionable bugs/requests). ## Project tooling @@ -14,16 +15,23 @@ This repository uses: - **pytest** for tests - **towncrier** for changelog fragments (only for user-facing changes) +CI runs: +- `pre-commit` (lint/format) +- `pytest` on multiple Python versions (matrix) + ## Quickstart ```bash -git clone -cd +git clone https://github.com/devqubit-labs/devqubit.git +cd devqubit -# Create/update .venv and install the workspace environment. +# Create/update .venv and install the workspace environment from uv.lock. # --all-packages installs all workspace members. -# --all-extras installs all optional dependencies (extras) for all members. -uv sync --all-packages --all-extras +# dev dependencies are synced by default (unless you opt out +uv sync --locked --all-packages + +# OPTIONAL: install all extras (optional dependencies) as well +uv sync --locked --all-packages --all-extras # Install git hooks (required) uv run pre-commit install @@ -38,7 +46,7 @@ uv run pytest If you only want the core packages and want to avoid heavy adapter/UI dependencies: ```bash -uv sync --all-packages +uv sync --locked --all-packages uv run pytest ``` @@ -182,21 +190,23 @@ Keep PRs focused and small when possible. If a change is large, split it into in If you change dependencies: -1. Update the relevant `pyproject.toml` +1. Update the relevant `pyproject.toml` (or use `uv add` / `uv remove`) 2. Update the lockfile and re-sync: ```bash uv lock -uv sync +uv sync --locked --all-packages ``` If you want to upgrade locked versions: ```bash uv lock --upgrade -uv sync +uv sync --locked --all-packages ``` +Tip: If `uv sync --locked` fails, it usually means uv.lock is out of date - run `uv lock` and commit the updated lockfile. + ## Documentation - If your change affects the CLI, update help text, docs, or examples. @@ -215,7 +225,7 @@ When filing a bug report, please include: Please do **not** report security vulnerabilities via public GitHub issues. -Instead, email: **info@devqubit.com** +Use GitHub “Report a vulnerability” (Private Vulnerability Reporting). ## License diff --git a/README.md b/README.md index e9630ce..74503e8 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ so runs are reproducible, comparable, and easy to share. ## Documentation -📚 Read the Docs: **https://.readthedocs.io** +📚 Read the Docs: **https://devqubit.readthedocs.io** The documentation source lives in this repository under `docs/`, but the canonical, rendered docs are on Read the Docs. diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..b971dc6 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,15 @@ +# Security Policy + +## Reporting a Vulnerability + +Please report security vulnerabilities privately. + +Use GitHub "Report a vulnerability" (Private Vulnerability Reporting). + +## Response Timeline + +We aim to respond within 72 hours, and provide a fix or mitigation plan as soon as possible. + +## Supported Versions + +We support the latest released minor version (and the latest patch of older minors when feasible). diff --git a/docs/getting-started/installation.md b/docs/getting-started/installation.md index 0135a25..c107610 100644 --- a/docs/getting-started/installation.md +++ b/docs/getting-started/installation.md @@ -25,11 +25,11 @@ devqubit --version Pick your SDK: ```bash -pip install devqubit-qiskit # IBM Qiskit (local, Aer) -pip install devqubit-qiskit-runtime # IBM Qiskit Runtime (cloud primitives) -pip install devqubit-braket # Amazon Braket -pip install devqubit-cirq # Google Cirq -pip install devqubit-pennylane # Xanadu PennyLane +pip install devqubit[qiskit] # IBM Qiskit (local, Aer) +pip install devqubit[qiskit-runtime] # IBM Qiskit Runtime (cloud primitives) +pip install devqubit[braket] # Amazon Braket +pip install devqubit[cirq] # Google Cirq +pip install devqubit[pennylane] # Xanadu PennyLane ``` ## Where data is stored diff --git a/pyproject.toml b/pyproject.toml index d7a2c20..243032c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -35,7 +35,7 @@ dependencies = [ Homepage = "https://devqubit.com" Repository = "https://github.com/devqubit-labs/devqubit" Issues = "https://github.com/devqubit-labs/devqubit/issues" -Documentation = "https://" +Documentation = "https://devqubit.readthedocs.io" [project.optional-dependencies] # Remote storage dependencies diff --git a/src/devqubit/__init__.py b/src/devqubit/__init__.py index 7d44105..75f7f83 100644 --- a/src/devqubit/__init__.py +++ b/src/devqubit/__init__.py @@ -28,9 +28,14 @@ >>> result = verify_against_baseline(candidate, project="my_project", policy=VerifyPolicy()) >>> assert result.ok +Snapshots +--------- +>>> from devqubit.snapshot import ExecutionEnvelope, DeviceSnapshot +>>> envelope = ExecutionEnvelope(device=device_snapshot, ...) + UI ------------ ->>> from devqubit_ui import run_server +>>> from devqubit import run_server >>> run_server(port=8080) Submodules @@ -39,6 +44,7 @@ - devqubit.ci: CI/CD integration (JUnit, GitHub annotations) - devqubit.bundle: Run packaging utilities - devqubit.config: Configuration management +- devqubit.snapshot: UEC snapshot schemas """ from __future__ import annotations diff --git a/src/devqubit/snapshot.py b/src/devqubit/snapshot.py new file mode 100644 index 0000000..47a1784 --- /dev/null +++ b/src/devqubit/snapshot.py @@ -0,0 +1,78 @@ +# SPDX-License-Identifier: Apache-2.0 +# SPDX-FileCopyrightText: 2026 devqubit + +""" +Uniform Execution Contract (UEC) snapshot schemas. + +This module provides standardized types for capturing quantum experiment state +across all supported SDKs. The UEC defines four canonical snapshot types plus +a unified envelope container. + +Basic Usage +----------- +>>> from devqubit.snapshot import ExecutionEnvelope +>>> envelope = ExecutionEnvelope( +... device=device_snapshot, +... program=program_snapshot, +... execution=execution_snapshot, +... result=result_snapshot, +... ) + +Validation +---------- +>>> from devqubit.snapshot import ValidationResult +>>> result = envelope.validate_schema() +>>> if result.valid: +... print("Schema valid") +""" + +from __future__ import annotations + +from typing import TYPE_CHECKING, Any + + +__all__ = [ + "ExecutionEnvelope", + "DeviceSnapshot", + "ProgramSnapshot", + "ExecutionSnapshot", + "ResultSnapshot", + "ValidationResult", +] + + +if TYPE_CHECKING: + from devqubit_engine.core.snapshot import ( + DeviceSnapshot, + ExecutionEnvelope, + ExecutionSnapshot, + ProgramSnapshot, + ResultSnapshot, + ValidationResult, + ) + + +_LAZY_IMPORTS = { + "ExecutionEnvelope": ("devqubit_engine.snapshot", "ExecutionEnvelope"), + "DeviceSnapshot": ("devqubit_engine.snapshot", "DeviceSnapshot"), + "ProgramSnapshot": ("devqubit_engine.snapshot", "ProgramSnapshot"), + "ExecutionSnapshot": ("devqubit_engine.snapshot", "ExecutionSnapshot"), + "ResultSnapshot": ("devqubit_engine.snapshot", "ResultSnapshot"), + "ValidationResult": ("devqubit_engine.snapshot", "ValidationResult"), +} + + +def __getattr__(name: str) -> Any: + """Lazy import handler.""" + if name in _LAZY_IMPORTS: + module_path, attr_name = _LAZY_IMPORTS[name] + module = __import__(module_path, fromlist=[attr_name]) + value = getattr(module, attr_name) + globals()[name] = value + return value + raise AttributeError(f"module {__name__!r} has no attribute {name!r}") + + +def __dir__() -> list[str]: + """List available attributes.""" + return sorted(set(__all__) | set(_LAZY_IMPORTS.keys()))