Changelog
=========

All notable changes to qubit-os-core are documented in this file.

Format reference: Keep a Changelog 1.1.0.
Versioning policy: Semantic Versioning.

Unreleased
----------

0.7.3 - 2026-06-01
------------------

Fixed

- GPU SME backend: the adaptive-dt substep retry condition was
  mis-parenthesized, so a stiff trajectory could retry forever at the dt
  floor. The batched and GPU backends now share one ``needs_substep_retry``
  decision, pinned by a truth-table test.
- The ``GateType`` deprecation in ``pulsegen.grape`` now names the correct
  removal version (``v0.8.0``); it previously said ``v0.4.0``.
- ``qubit-os --version`` reports the package version correctly: the
  ``pyproject.toml`` version had lagged at ``0.7.1``.

Changed

- The CLI decoherence/error-budget display catches only ``CalibrationError``
  (bad or missing calibration files), so bugs in the display helpers surface
  instead of being reported as "calibration could not load".
- ``rust_crossval_golden.json`` now records both Python and Rust GRAPE results,
  and the golden test asserts the two converge and agree on achieved fidelity.
  It was previously a Python-only self-consistency check.

Added

- ``gpu`` optional dependency (CuPy) and a registered ``gpu`` test marker.
- The cross-validation CI gate fails on a skipped non-GPU crossval test
  (``QUBITOS_REQUIRE_CROSSVAL``), closing a silent-skip gap.
- Lint tripwires: ruff ``BLE`` (blind-except), pytest ``--strict-markers``, and
  clippy ``todo``/``unimplemented``/``dbg_macro`` denials.

0.7.2 - 2026-05-27
------------------

Changed

- ``__version__`` is now ``0.7.2``.
- CLI error reporting is centralized in a single group-level handler, so
  every command reports an uncaught error in the same
  ``Error (<Type>): <message>`` format. ``calibration validate`` failures
  previously used a ``Validation error:`` prefix.
- ``HALClient.connect`` now surfaces the specific gRPC status code
  (e.g. ``UNAVAILABLE``) for transport failures instead of a generic
  ``CONNECTION_ERROR``.
- The ``GateType`` deprecation now targets removal in ``v0.8.0`` and points
  callers to ``from qubitos.target_unitary import TargetUnitary``.

Removed

- ``qubitos.validation``: the ``AgentBibleValidator`` facade,
  ``is_agentbible_available``, ``get_agentbible_import_error``,
  ``default_validator``, and the ``validate_hamiltonian`` /
  ``validate_pulse`` / ``validate_calibration`` convenience passthroughs.
  Use the direct validators (``validate_hermitian``,
  ``validate_pulse_envelope``, ``validate_calibration_t1_t2``).
- The ``TargetUnitary`` re-export from ``qubitos.pulsegen``; import it from
  ``qubitos.target_unitary`` instead.

0.7.1 - 2026-05-21
-------------------

Added

- ``noise_sweep_comparison(..., max_workers=..., checkpoint_dir=...)``:
  optional process-pool parallelism over independent ``(method, noise)``
  cells (default uses ``min(os.cpu_count(), n_noise * n_methods)`` workers
  with a ``spawn`` multiprocessing context for fork-safety) and optional
  per-cell ``.npz`` checkpoints for resumable long sweeps.
- ``noise_sweep_comparison(..., log_path=...)``: optional structured JSONL
  log with one record per cell ``start`` / ``done`` / ``error`` event and
  a ``resume`` record when prior checkpoints are picked up. Each record
  carries a UTC timestamp, the ``(noise_idx, method_idx, method)``
  coordinates, ``wall_s``, and (on ``done``) ``mean_fidelity``. Events
  are also emitted at ``INFO`` to the
  ``qubitos.feedback.analysis.sweep`` logger for callers that prefer the
  stdlib ``logging`` route. This makes long sweeps observable in real
  time without changing the default (silent) behavior.

Changed

- Per-cell RNG seeds now derive from ``numpy.random.SeedSequence(seed)``
  with flat index ``k = method_idx * n_noise + noise_idx`` (replacing the
  v0.7.0 ad-hoc integer offset). Parallel and serial paths are bit-identical
  for the same inputs and base seed; rerun v0.7.0 regression artifacts if
  you require numeric continuity with the old formula.

Fixed

- Long single-core noise sweeps can use multiple cores without changing
  reproducibility semantics (explicit ``max_workers=1`` keeps the
  in-process loop and avoids worker startup).

0.7.0 - 2026-05-16
-------------------

Added

Lyapunov Feedback Controller (v0.7.0)
- `qubitos.feedback`: closed-loop controller that consumes the v0.6.0
  SME runtime and emits a real-time correction to the drive Hamiltonian
- Lyapunov function `V(rho_c) = 1 - Tr[rho_target rho_c]` and feedback
  law `delta_Omega_k(t) = -K_k * Tr[rho_target * [i sigma_k / 2, rho_c]]`
- `LyapunovController` with diagonal gain (scalar or per-axis), opt-in
  full 3x3 gain matrix, and amplitude saturation
- `solve_with_feedback` and `solve_with_feedback_ensemble` orchestrate
  the SME runtime + feedback law per nominal step, preserving the
  adaptive-timestep substep machinery so zero-gain reproduces
  `SMESolver.solve_trajectory` exactly
- `_FeedbackDelayBuffer` discrete-time latency aligned to the nominal
  SME step
- `build_feedback_delay_constraint` and `accumulate_feedback_delay`
  integrate feedback delay with the existing temporal/ machinery
  (SEQUENTIAL TemporalConstraint, DecoherenceBudget block_fraction)
- `qubitos.feedback.analysis`: `noise_sweep_comparison`,
  `crossover_point`, `build_baseline_hamiltonians`, `HardwareParams`,
  `default_iqm_garnet_params`, `NoiseSweepResult`
- `qubitos.feedback.viz`: `plot_lyapunov_trajectory`,
  `plot_bloch_trajectory` (via qutip.Bloch), `plot_noise_sweep`
- AgentBible decoration on the Lyapunov scalar output and the
  trajectory-level Lyapunov vector at the module boundary
- 117 feedback tests in the core tree (105 fast unit + 12 slow
  integration), covering the Tier-5 validation gates from
  SME-FEEDBACK-SPEC section 4.5: zero-gain identity, ensemble-mean V(t)
  trend, V(t) noise-floor behaviour, |1> stabilization counteracting T1,
  noise-sweep crossover smoke
- Tutorial: `core/docs/tutorials/lyapunov-feedback.txt`
- 7 Rust crossvalidation tests for the
  `qubit_os_hardware.feedback.RustLyapunovController` (gated on the
  Python extension being available)

Changed

- `matplotlib >= 3.7` added as a `core` runtime dependency (used by the
  visualization helpers)
- `_grape_baseline` in `qubitos.feedback.analysis` doubles the GRAPE
  envelope scale to match the SME's `omega * sigma / 2` Hamiltonian
  convention (GRAPE optimizes against `H = i * sigma_x + q * sigma_y`
  with no 1/2 factor; the SME runtime uses the 1/2 factor)
- `qubitos.feedback.analysis._drag_baseline` uses a dimensionally
  consistent `omega_q = -beta * sigma * dOmega/dt` Q-component
- `SME-FEEDBACK-SPEC.txt` status header updated to reflect v0.7.0
  surfaces (sections 0-4 in v0.6.0, sections 1.4 + 2 + comparison
  framework + Tier 5 in v0.7.0); the diagonal-gain validated path and
  the opt-in full 3x3 K matrix path are now documented in section 1.4

0.6.0 - 2026-05-16
-------------------

Added

Stochastic Master Equation Solver (v0.6.0)
- `qubitos.sme`: Python SME reference solver with single trajectories and
  Monte Carlo ensembles
- Euler-Maruyama integration for the Itô stochastic master equation
- Adaptive timestep retry logic using trace-norm monitoring
- Homodyne measurement superoperator, measurement record simulation, and
  positivity monitoring with optional projection
- AgentBible-backed density-matrix validation at the SME module boundary
- 79 SME tests currently active in the core tree (77 unit + 2 fast integration)
- QuTiP `smesolve()` cross-validation test and ensemble convergence checks

Changed

- `qubitos.lindblad`: added reusable RHS / RK4 helpers and
  `from_sme_ensemble(...)` convergence check support
- Packaging metadata now points at `README.txt`, matching the plain-text
  documentation policy

0.5.0 - 2026-02-09
-------------------

Added

Lindblad Simulation (v0.5.2)
- **Lindblad solver** (`qubitos.lindblad`): Full Python mirror of Rust Lindblad API
  - Open quantum system simulation: ρ̇ = -i[H,ρ] + Σ D[Lk](ρ)
  - T1/T2 decoherence: amplitude damping and phase damping collapse operators
  - State fidelity, trace distance, Hellinger distance metrics
  - 22 tests including 4 cross-validation tests against QuTiP mesolve()

0.4.0 - 2026-02-09
-------------------

Added

Active Calibration (0.4.1)
- **DriftMonitor**: Real-time drift detection comparing calibration fingerprints against baseline
  - Five severity levels: NONE, LOW, MODERATE, HIGH, CRITICAL
  - Per-qubit drift identification with affected parameter breakdown
  - Configurable thresholds for frequency, T1/T2, and gate fidelity
  - `DriftEvent` frozen dataclass with severity, metrics, and summary
- **RecalibrationPolicy**: Three strategies for automated recalibration
  - `selective`: Recalibrate only affected qubits (fastest recovery)
  - `full`: Recalibrate all qubits (most thorough)
  - `adaptive`: Selective for HIGH drift, full for CRITICAL
  - Cooldown timer to prevent rapid recalibration cascades
- **ActiveCalibrationLoop**: Async feedback control loop
  - `run_once()` for testable single-cycle execution
  - Action types: MEASURED, DRIFT_DETECTED, RECALIBRATED, ERROR, SKIPPED
  - Full action history tracking with cycle counting
  - Ref: Kelly et al. (2016), Phys. Rev. A 94, 032321. arXiv:1603.03082
- **Provenance integration**: DRIFT_EVENT and RECALIBRATION node types in Merkle tree
  - `ProvenanceBuilder.add_drift_event()`: Record drift detection events
  - `ProvenanceBuilder.add_recalibration()`: Record recalibration actions
  - Deterministic hashing for audit trail reproducibility

GRAPE in Rust (0.4.2) — qubit-os-hardware
- **Rust GRAPE optimizer**: Full port from Python to Rust using `ndarray`
  - Matrix exponential via Padé(13) scaling-and-squaring (Higham 2005)
  - Forward/backward propagator chains
  - Nielsen (2002) average gate fidelity
  - Analytic gradient computation (Khaneja et al. 2005)
  - Adaptive learning rate matching Python implementation
  - X gate convergence: >0.90 fidelity in 154 iterations
- **PyO3 bindings**: `RustGrapeOptimizer` callable from Python
  - Drop-in interface matching Python `GrapeConfig`/`GrapeResult`
  - Flat complex array marshalling for zero-copy potential
- **Cross-validation tests**: Python vs Rust GRAPE comparison (requires PyO3 build)

0.3.0 - 2026-02-08
-------------------

Added

Multi-Qubit GRAPE Optimization (v0.3.0, Phase 3a)
- Per-qubit pulse envelopes: shape `(n_qubits, n_steps)` for multi-qubit control
- `build_drift_hamiltonian()`: rotating-frame drift with qubit detunings + ZZ coupling
- Dimension-scaled adaptive learning rate: `(d²+d)/6` compensates gradient normalization
- Results: 2-qubit CZ/CNOT at 95%+ fidelity (from 40% random baseline), 3-qubit Toffoli functional

Pulse Scheduler (v0.3.0, Phase 3b)
- `PulseScheduler` with ASAP scheduling via topological sort (Kahn's algorithm)
- Constraint-based scheduling: SEQUENTIAL, SIMULTANEOUS, ALIGNED, MAX_DELAY
- Automatic qubit-conflict avoidance (no overlap on same qubit)
- Crosstalk-aware scheduling: coupled qubit pairs serialized automatically
- AWG clock grid alignment for all start times
- ASCII timeline visualization (`ScheduleResult.ascii_timeline()`)
- Schedule metrics: makespan, parallelism, per-qubit utilization

Three-Qubit Gates
- `GATE_TOFFOLI` (CCX): Toffoli gate (8×8 unitary)
- `GATE_FREDKIN` (CSWAP): Fredkin gate (8×8 unitary)
- `TargetUnitary` enum: TOFFOLI, CCX, FREDKIN, CSWAP (Python-only, proto in v0.4.0)

Parametric Two-Qubit Gates (v0.3.0, Phase 3c)
- `fsim_gate(theta, phi)`: fSim gate family (Google Sycamore style)
- `cross_resonance_unitary(zx, ix, zi)`: Cross-resonance gate (IBM style)

Symplectic Clifford Representation (v0.3.0, Phase 3d)
- `CliffordTableau`: (2n×2n) binary symplectic matrix + phase vector
- Composition, inverse, and to_unitary() conversion
- `sample_random_clifford()`: random n-qubit Clifford sampling
- `generate_multiqubit_rb_sequence()`: multi-qubit RB sequence generation
- Elementary gate tableaux: Hadamard, S, CNOT

0.2.0 - 2026-02-08
-------------------

Added

Time Model & Temporal Constraints (GAP 1)
- `TimePoint` type with `nominal_ns`, `precision_ns`, and `jitter_bound_ns`
- `AWGClockConfig` for clock alignment with `sample_rate_ghz` and quantization
- `TemporalConstraint` system: `Simultaneous`, `Sequential`, `Aligned`, `MaxDelay`, `MinGap`
- `PulseSequence` data structure with constraint validation at construction time
- `DecoherenceBudget` tracking cumulative T1/T2 consumption across sequences
- 88 temporal module tests
- CLI integration: `--sample-rate` for AWG alignment, decoherence budget display

Error Budget System (GAP 2)
- `ErrorBudget` dataclass with `projected_fidelity()` and `can_append()` methods
- Configurable warning thresholds (50% warn, 90% reject by default)
- Integration with calibration T1/T2 data for decoherence cost calculation
- Proto roundtrip tests for error budget messages

Hamiltonian-First API Restructure (GAP 5)
- **NEW:** `TargetUnitary` enum in `qubitos.target_unitary` as single source of truth
- **NEW:** `TARGET_UNITARIES` dict in `hamiltonians.py` with all preset matrices
- `SQISWAP` (√iSWAP) gate matrix added
- `I` (Identity) and `UNSPECIFIED` members added to enum
- `TargetUnitary.is_parametric` and `TargetUnitary.num_qubits` properties
- Proto field number mapping for cross-repo consistency
- CLI: `--target-unitary` flag (primary), `--gate` deprecated

Experiment Provenance Merkle Tree (GAP 4)
- `provenance` module: `ProvenanceBuilder`, `ProvenanceTree`, `ProvenanceStore`
- Merkle tree with nodes: Calibration, QubitCalibration, CouplerCalibration,
  PulseSequence, ScheduledPulse, GRAPEConfig, SoftwareVersion
- `diff()` for identifying exactly what changed between two experiments
- SHA-256 hashing: canonical JSON for leaves, sorted child hashes for internals
- Float canonicalization to 12 significant digits for deterministic hashing
- Raw byte envelope hashing for performance
- JSON serialization round-trip (`to_dict` / `from_dict`)
- `ProvenanceStore` with LRU eviction and optional JSON persistence
- 42 provenance tests covering hashing, tree structure, diff, serialization, store

Changed
- `GateType` deprecated — use `TargetUnitary` instead (removal in v0.4.0)
- `STANDARD_GATES` is now an alias for `TARGET_UNITARIES`
- `generate_pulse()` and `get_target_unitary()` accept `TargetUnitary` enum or string
- CLI `--gate` flag deprecated in favor of `--target-unitary`
- `GrapeConfig.duration_ns` type changed from `float` to `int` (matches proto `int32`)

Fixed
- Replaced proto stubs with prost re-exports in Rust HAL (B1)
- Rewrote gRPC server to implement generated trait (B2)
- Synced Python gate enums with proto definitions — S, T, CX, SQISWAP, SWAP (B3)
- Fixed `duration_ns` float→int type mismatch (B4)
- Corrected API documentation for GRAPE optimizer (B6)
- Added `serial_test` for flaky environment tests (B7)
- Migrated `serde_yaml` to `serde_yml` in Rust HAL
- Fixed prost/tonic version skew between proto and hardware crates

Changed
- Improved documentation structure and navigation

0.1.0 - 2026-02-03
-------------------

Added

Core Functionality
- **GRAPE Optimizer** (`qubitos.pulsegen.grape`)
  - `GrapeOptimizer` class with gradient ascent pulse engineering
  - `GrapeConfig` dataclass for optimizer configuration
  - `GrapeResult` dataclass for optimization results
  - `generate_pulse()` convenience function
  - Adaptive learning rate with momentum
  - L2 regularization for pulse smoothness
  - Callback support for progress monitoring

- **Hamiltonian Utilities** (`qubitos.pulsegen.hamiltonians`)
  - Pauli string parsing: `parse_pauli_string()`
  - Tensor product construction: `tensor_product()`
  - Standard gate unitaries (X, Y, Z, H, CZ, CNOT, iSWAP, etc.)
  - Rotation gates: `rotation_gate()`
  - Gate embedding: `embed_gate()`

- **HAL Client** (`qubitos.client`)
  - `HALClient` async gRPC client
  - `HALClientSync` synchronous wrapper
  - Automatic reconnection and retry logic
  - Connection pooling

- **Calibration** (`qubitos.calibrator`)
  - `CalibrationLoader` for loading calibration files
  - `BackendCalibration` dataclass
  - `QubitCalibration` dataclass
  - JSON and YAML format support
  - OpenPulse compatibility

- **Validation** (`qubitos.validation`)
  - `validate_pulse()` for pulse envelope validation
  - `validate_config()` for configuration validation
  - `AgentBibleValidator` for constraint enforcement
  - Comprehensive error messages

- **CLI** (`qubitos.cli`)
  - `qubit-os pulse generate` - Generate optimized pulses
  - `qubit-os pulse show` - Display pulse information
  - `qubit-os calibration load` - Load calibration data
  - `qubit-os calibration validate` - Validate calibration
  - `qubit-os hal status` - Check HAL server status
  - `qubit-os hal execute` - Execute pulse on hardware
  - Rich terminal output with tables and progress bars

Documentation
- Installation guide with all dependency options
- Quickstart tutorial with basic examples
- Troubleshooting guide with common issues
- First pulse tutorial
- Calibration guide
- Custom Hamiltonians tutorial
- API reference for all modules
- CLI command reference
- REST API documentation
- gRPC service documentation
- Jupyter notebooks:
  - 01-quickstart.ipynb
  - 02-grape-optimization.ipynb
  - 03-custom-hamiltonians.ipynb

Infrastructure
- GitHub Actions CI/CD pipeline
- pytest test suite with coverage
- mypy type checking
- ruff linting and formatting
- pre-commit hooks
- MkDocs documentation site
- OpenAPI specification

Dependencies
- Python >= 3.11
- numpy >= 1.26
- scipy >= 1.12
- grpcio >= 1.60
- protobuf >= 4.25
- click >= 8.0
- pydantic >= 2.5
- rich >= 13.0
- Optional: matplotlib, jupyter, qutip

0.0.1 - 2026-01-26
-------------------

Added
- Initial project structure
- Python package scaffolding (qubitos)
- CLI skeleton with click
- Default calibration for QuTiP simulator
- OpenAPI specification for REST API
- GitHub Actions CI workflow
