Initial import
This commit is contained in:
@@ -0,0 +1,308 @@
|
||||
# Sub-plan 1 — Foundation (Tasks 1–3)
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development or superpowers:executing-plans.
|
||||
|
||||
**Goal:** Cargo bootstrap + error types + domain newtypes + Backend trait hierarchy. Produces a compiling skeleton with all dependencies resolved.
|
||||
|
||||
**Starting state:** Greenfield — only `CLAUDE.md`, `.gitignore`, and `docs/` exist. No `src/`, no `Cargo.toml`.
|
||||
|
||||
**Deliverable:** `cargo test` exits 0. Three commits in git history.
|
||||
|
||||
**Tech Stack:** Rust 2021, `rmcp` (git), `oq3_semantics 0.7`, `spinoza 0.5`, `tokio`, `serde`, `thiserror 2`, `tracing`.
|
||||
|
||||
**Main plan reference:** `docs/superpowers/plans/2026-04-28-quantum-bridge-mcp-v1.md` Tasks 1–3.
|
||||
|
||||
---
|
||||
|
||||
## Task 1: Bootstrap
|
||||
|
||||
**Files:**
|
||||
- Create: `Cargo.toml`
|
||||
- Create: `src/main.rs` (via `cargo new`)
|
||||
|
||||
- [ ] **Step 1: Initialise project**
|
||||
|
||||
```bash
|
||||
cd /home/vincent/src/misc/quantum-bridge-mcp
|
||||
cargo new --name quantum-bridge-mcp .
|
||||
```
|
||||
|
||||
Expected: `src/main.rs` and `Cargo.toml` created.
|
||||
|
||||
- [ ] **Step 2: Write Cargo.toml**
|
||||
|
||||
> Run `cargo search spinoza` and `cargo search oq3_semantics` to confirm latest patch versions before pinning.
|
||||
|
||||
```toml
|
||||
[package]
|
||||
name = "quantum-bridge-mcp"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
description = "Zero-dependency MCP server for local OpenQASM 3.0 quantum circuit simulation"
|
||||
license = "MIT"
|
||||
|
||||
[dependencies]
|
||||
rmcp = { git = "https://github.com/modelcontextprotocol/rust-sdk", features = ["server", "transport-io", "macros"] }
|
||||
oq3_semantics = "0.7"
|
||||
spinoza = "0.5"
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
schemars = "0.8"
|
||||
thiserror = "2"
|
||||
tracing = "0.1"
|
||||
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
||||
anyhow = "1"
|
||||
|
||||
[dev-dependencies]
|
||||
proptest = "1"
|
||||
criterion = { version = "0.5", features = ["html_reports"] }
|
||||
|
||||
[[bench]]
|
||||
name = "simulation"
|
||||
harness = false
|
||||
```
|
||||
|
||||
- [ ] **Step 3: Write minimal src/main.rs**
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
println!("quantum-bridge-mcp");
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 4: Verify dependencies compile**
|
||||
|
||||
```bash
|
||||
cargo build
|
||||
```
|
||||
|
||||
Expected: success (first run ~200 MB). If a version constraint fails, run `cargo search <crate>` and adjust.
|
||||
|
||||
- [ ] **Step 5: Commit**
|
||||
|
||||
```bash
|
||||
git add Cargo.toml Cargo.lock src/main.rs
|
||||
git commit -m "chore: bootstrap project with all V1 dependencies"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 2: Foundation — Error types and domain newtypes
|
||||
|
||||
**Files:**
|
||||
- Create: `src/error.rs`
|
||||
- Create: `src/types.rs`
|
||||
- Modify: `src/main.rs`
|
||||
|
||||
- [ ] **Step 1: Write src/error.rs**
|
||||
|
||||
```rust
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum BridgeError {
|
||||
#[error("parse error at line {line}, col {col}: {message}")]
|
||||
Parse { line: usize, col: usize, message: String },
|
||||
|
||||
#[error("gate '{gate}' is not supported at line {line} — supported: {supported}")]
|
||||
UnsupportedGate { gate: String, line: usize, supported: String },
|
||||
|
||||
#[error("qubit index {index} is out of range (circuit declares {declared} qubits)")]
|
||||
QubitOutOfRange { index: usize, declared: usize },
|
||||
|
||||
#[error("circuit requires {requested} qubits, exceeds the local simulator limit of {limit}")]
|
||||
QubitLimitExceeded { requested: usize, limit: usize },
|
||||
|
||||
#[error("simulation failed: {0}")]
|
||||
Simulation(String),
|
||||
|
||||
#[error("measure at line {line} maps to an undeclared classical bit")]
|
||||
MeasurementMapping { line: usize },
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Write src/types.rs**
|
||||
|
||||
```rust
|
||||
use std::collections::HashMap;
|
||||
|
||||
/// Newtype for qubit indices — prevents mixing with plain usizes.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct QubitIndex(pub usize);
|
||||
|
||||
/// Newtype for shot count — enforces range and intent at type level.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct ShotCount(pub u32);
|
||||
|
||||
impl ShotCount {
|
||||
pub const DEFAULT: ShotCount = ShotCount(1024);
|
||||
pub const MAX: ShotCount = ShotCount(100_000);
|
||||
}
|
||||
|
||||
/// Wraps an OpenQASM 3.0 source string.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct CircuitSource(pub String);
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum DiagnosticSeverity {
|
||||
Error,
|
||||
Warning,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ValidationDiagnostic {
|
||||
pub line: usize,
|
||||
pub column: usize,
|
||||
pub message: String,
|
||||
pub severity: DiagnosticSeverity,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ValidationResult {
|
||||
pub is_valid: bool,
|
||||
pub diagnostics: Vec<ValidationDiagnostic>,
|
||||
pub num_qubits: Option<usize>,
|
||||
pub num_gates: Option<usize>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct SimulationResult {
|
||||
/// Bitstring → count, e.g. `{"00": 512, "11": 512}`.
|
||||
pub counts: HashMap<String, u64>,
|
||||
pub shots: u32,
|
||||
pub execution_time_ms: f64,
|
||||
/// Optional full statevector as (real, imag) pairs per basis state.
|
||||
pub statevector: Option<Vec<(f64, f64)>>,
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 3: Update src/main.rs**
|
||||
|
||||
```rust
|
||||
mod error;
|
||||
mod types;
|
||||
|
||||
fn main() {
|
||||
println!("quantum-bridge-mcp");
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 4: Verify**
|
||||
|
||||
```bash
|
||||
cargo build
|
||||
```
|
||||
|
||||
Expected: no warnings.
|
||||
|
||||
- [ ] **Step 5: Commit**
|
||||
|
||||
```bash
|
||||
git add src/error.rs src/types.rs src/main.rs
|
||||
git commit -m "feat: add error types and domain newtypes"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 3: Backend Traits
|
||||
|
||||
**Files:**
|
||||
- Create: `src/executor.rs` (traits + constants only — `LocalSimulator` comes in sub-plan 3)
|
||||
|
||||
- [ ] **Step 1: Write src/executor.rs**
|
||||
|
||||
```rust
|
||||
use crate::error::BridgeError;
|
||||
use crate::types::{CircuitSource, ShotCount, SimulationResult, ValidationResult};
|
||||
|
||||
pub const MAX_LOCAL_QUBITS: usize = 28;
|
||||
|
||||
pub const SUPPORTED_GATES: &[&str] = &[
|
||||
"h", "x", "y", "z", "s", "t", "sdg", "tdg",
|
||||
"rx", "ry", "rz", "cx", "cz", "swap", "ccx",
|
||||
"measure",
|
||||
];
|
||||
|
||||
pub trait CanIntrospect {
|
||||
fn name(&self) -> &str;
|
||||
fn max_qubits(&self) -> usize;
|
||||
fn supported_gates(&self) -> &[&str];
|
||||
}
|
||||
|
||||
pub trait CanValidate {
|
||||
fn validate(&self, circuit: &CircuitSource) -> Result<ValidationResult, BridgeError>;
|
||||
}
|
||||
|
||||
pub trait CanExecute {
|
||||
fn run(
|
||||
&self,
|
||||
circuit: &CircuitSource,
|
||||
shots: ShotCount,
|
||||
return_statevector: bool,
|
||||
) -> Result<SimulationResult, BridgeError>;
|
||||
}
|
||||
|
||||
/// Marker trait combining all three capabilities. V1.5 IBM backend will impl this too.
|
||||
pub trait Backend: CanIntrospect + CanValidate + CanExecute + Send + Sync {}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
struct MockBackend;
|
||||
impl CanIntrospect for MockBackend {
|
||||
fn name(&self) -> &str { "mock" }
|
||||
fn max_qubits(&self) -> usize { 4 }
|
||||
fn supported_gates(&self) -> &[&str] { SUPPORTED_GATES }
|
||||
}
|
||||
impl CanValidate for MockBackend {
|
||||
fn validate(&self, _: &CircuitSource) -> Result<ValidationResult, BridgeError> {
|
||||
Ok(ValidationResult { is_valid: true, diagnostics: vec![], num_qubits: None, num_gates: None })
|
||||
}
|
||||
}
|
||||
impl CanExecute for MockBackend {
|
||||
fn run(&self, _: &CircuitSource, _: ShotCount, _: bool) -> Result<SimulationResult, BridgeError> {
|
||||
Ok(SimulationResult { counts: Default::default(), shots: 0, execution_time_ms: 0.0, statevector: None })
|
||||
}
|
||||
}
|
||||
impl Backend for MockBackend {}
|
||||
|
||||
#[test]
|
||||
fn mock_backend_satisfies_trait_bounds() {
|
||||
let b = MockBackend;
|
||||
assert_eq!(b.name(), "mock");
|
||||
assert_eq!(b.max_qubits(), 4);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Declare module and run tests**
|
||||
|
||||
Add to `src/main.rs`:
|
||||
```rust
|
||||
mod executor;
|
||||
```
|
||||
|
||||
```bash
|
||||
cargo test
|
||||
```
|
||||
|
||||
Expected: 1 test passes (`mock_backend_satisfies_trait_bounds`).
|
||||
|
||||
- [ ] **Step 3: Commit**
|
||||
|
||||
```bash
|
||||
git add src/executor.rs src/main.rs
|
||||
git commit -m "feat: define Backend trait hierarchy (CanIntrospect/CanValidate/CanExecute)"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Final verification
|
||||
|
||||
```bash
|
||||
cargo fmt --check && cargo clippy -- -D warnings && cargo test
|
||||
```
|
||||
|
||||
Expected: all green. Sub-plan 1 complete — hand off to sub-plan 2.
|
||||
Reference in New Issue
Block a user