Files
quantum-bridge-mcp/docs/superpowers/plans/sub1-foundation.md
T
Vincent Bourdon 9af114e391 Initial import
2026-06-09 16:14:55 +02:00

309 lines
7.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Sub-plan 1 — Foundation (Tasks 13)
> **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 13.
---
## 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.