| ## Phase 0/1/2 Integration Guide |
|
|
| This document explains how the three phases of the agentic quantum dot tuning system integrate together. |
|
|
| --- |
|
|
| ## Architecture Overview |
|
|
| ``` |
| ┌─────────────────────────────────────────────────────────────────────┐ |
| │ EXECUTIVE AGENT (Phase 2) │ |
| │ Main orchestration loop (Fig. 2) │ |
| └─────────────────────────────────────────────────────────────────────┘ |
| │ |
| ┌─────────────────┼─────────────────┐ |
| │ │ │ |
| ▼ ▼ ▼ |
| ┌────────────────┐ ┌────────────┐ ┌─────────────┐ |
| │ PERCEPTION │ │ PLANNING │ │ HARDWARE │ |
| │ (Phase 1) │ │ (Phase 2) │ │ (Phase 0) │ |
| └────────────────┘ └────────────┘ └─────────────┘ |
| │ │ │ |
| │ - DQCGatekeeper │ - BeliefUpdater │ - DeviceAdapter |
| │ - InspectionAgent │ - ActiveSensingPolicy│ - SafetyCritic |
| │ - EnsembleCNN │ - MultiResBO │ - HITLManager |
| │ - OOD Detector │ - StateMachine │ - GovernanceLogger |
| │ │ - TranslationAgent │ |
| └───────────────────┴──────────────────────┴─────────────┘ |
| │ |
| ▼ |
| ┌─────────────────────┐ |
| │ EXPERIMENT STATE │ |
| │ (Phase 0) │ |
| │ Single source of │ |
| │ truth │ |
| └─────────────────────┘ |
| ``` |
|
|
| --- |
|
|
| ## Data Flow: One Complete Loop |
|
|
| ### 1. Active Sensing (Phase 2 Planning) |
| **ActiveSensingPolicy.select()** examines `ExperimentState.belief` and proposes a measurement: |
| ```python |
| plan = sensing_policy.select(state.belief, v1_range, v2_range) |
| # → MeasurementPlan(modality=COARSE_2D, v1_range=(-0.5, 0.5), ...) |
| ``` |
|
|
| ### 2. Translation (Phase 2 Agent) |
| **TranslationAgent.execute()** converts the plan to a DeviceAdapter call: |
| ```python |
| result = translator.execute(plan) |
| measurement = result.measurement # Measurement from CIMSimulatorAdapter |
| state.add_measurement(measurement) |
| ``` |
|
|
| ### 3. Data Quality Check (Phase 1 Perception) |
| **DQCGatekeeper.assess()** runs physics-based quality checks: |
| ```python |
| dqc_result = dqc.assess(measurement) |
| state.add_dqc_result(dqc_result) |
| |
| if dqc_result.quality == DQCQuality.LOW: |
| # STOP — do not pass to InspectionAgent |
| return failure_result |
| ``` |
|
|
| ### 4. Classification (Phase 1 Perception) |
| **InspectionAgent.inspect()** runs the full perception pipeline: |
| ```python |
| if measurement.is_2d: |
| classification, ood_result = inspector.inspect(measurement, dqc_result) |
| state.add_classification(classification) |
| state.add_ood_result(ood_result) |
| ``` |
|
|
| InspectionAgent internally: |
| - Log-preprocesses the array |
| - Runs EnsembleCNN (5-model ensemble) |
| - Extracts physics features (FFT peak ratio, diagonal strength) |
| - Checks for physics override |
| - Runs OOD detector on penultimate features |
| - Generates structured NL summary |
|
|
| ### 5. Belief Update (Phase 2 Planning) |
| **BeliefUpdater** updates the POMDP belief using CIM observation model: |
| ```python |
| belief_updater.update_from_2d(measurement, classification) |
| # Updates state.belief.charge_probs in-place |
| ``` |
|
|
| For line scans (bypass InspectionAgent per blueprint §5.1): |
| ```python |
| if measurement.modality == MeasurementModality.LINE_SCAN: |
| belief_updater.update_from_1d(measurement) |
| ``` |
|
|
| ### 6. Bayesian Optimization (Phase 2 Planning) |
| **MultiResBO.propose()** uses GP with CIM-informed priors: |
| ```python |
| bo.update(state.bo_history) |
| proposal = bo.propose(current=state.current_voltage, l1_max=0.10) |
| # → ActionProposal(delta_v=VoltagePoint(vg1=0.05, vg2=0.02), ...) |
| ``` |
|
|
| ### 7. Safety Critic (Phase 0 Hardware) |
| **SafetyCritic** enforces hard constraints: |
| ```python |
| proposal = safety_critic.clip(proposal, state.current_voltage) |
| verdict = safety_critic.verify(state.current_voltage, proposal) |
| |
| if not verdict.all_passed: |
| state.record_safety_violation() |
| return failure_result |
| ``` |
|
|
| ### 8. Risk Assessment + HITL (Phase 0 Governance) |
| **HITLManager.compute_risk_score()** aggregates 12 trigger conditions: |
| ```python |
| risk = hitl_manager.compute_risk_score( |
| proposal=proposal, |
| safety_verdict=verdict, |
| dqc_flag=dqc_result.quality.value, |
| ood_score=ood_result.score, |
| ensemble_disagreement=classification.ensemble_disagreement, |
| consecutive_backtracks=state.consecutive_backtracks, |
| step=state.step + 1, |
| ) |
| |
| if risk >= 0.70: |
| event = hitl_manager.queue_request(...) |
| event = hitl_manager.await_decision(event) # BLOCKS |
| state.add_hitl_event(event) |
| ``` |
|
|
| ### 9. Execute Move (Phase 2 Agent + Phase 0 Hardware) |
| If all checks pass: |
| ```python |
| translator.execute_voltage_move( |
| vg1=state.current_voltage.vg1 + safe_dv.vg1, |
| vg2=state.current_voltage.vg2 + safe_dv.vg2, |
| ) |
| state.apply_move(safe_dv) |
| ``` |
|
|
| ### 10. Governance (Phase 0) |
| **GovernanceLogger** records every action: |
| ```python |
| decision = Decision( |
| run_id=state.run_id, |
| step=state.step, |
| intent="voltage_move", |
| stage=state.stage, |
| observation_summary={...}, |
| action_summary={...}, |
| rationale="...", |
| ) |
| state.add_decision(decision) |
| governance_logger.log(decision) |
| ``` |
|
|
| ### 11. State Machine (Phase 2 Planning) |
| **StateMachine.process_result()** manages stage transitions: |
| ```python |
| result = navigation_result(target_reached=True, belief_confidence=0.85) |
| new_stage, rationale, hitl_triggered = state_machine.process_result(result) |
| |
| if new_stage != state.stage: |
| state.advance_stage(new_stage) |
| ``` |
| |
| Backtracking on failure: |
| ```python |
| if retries_exhausted: |
| event = BacktrackEvent(from_stage=NAVIGATION, to_stage=CHARGE_ID, ...) |
| state.record_backtrack(event) |
| ``` |
| |
| --- |
| |
| ## Key Integration Points |
| |
| ### BeliefState (Phase 0 stub → Phase 2 implementation) |
| |
| **Phase 0 defined the interface:** |
| ```python |
| @dataclass |
| class BeliefState: |
| charge_probs: Dict[tuple, float] = field(default_factory=dict) |
| uncertainty_map: Optional[Any] = None |
| device_params: Dict[str, float] = field(default_factory=lambda: {...}) |
| |
| def entropy(self) -> float: ... |
| def most_likely_state(self) -> Optional[tuple]: ... |
| def initialise_uniform(self, charge_states: Optional[List[tuple]] = None) -> None: ... |
| ``` |
|
|
| **Phase 2 implemented the particle filter:** |
| ```python |
| class BeliefUpdater: |
| def __init__(self, belief: BeliefState, ...): |
| self.belief = belief # Operates on Phase 0 stub directly |
| self._particles = _ParticleSet(...) # Internal engine |
| |
| def update_from_2d(self, measurement, classification): |
| # Updates self.belief.charge_probs in-place |
| self.belief.charge_probs = self._particles.to_charge_probs() |
| ``` |
|
|
| ### Classification Flow (Phase 1 → Phase 2) |
|
|
| **InspectionAgent output:** |
| ```python |
| classification = Classification( |
| measurement_id=..., |
| label=ChargeLabel.DOUBLE_DOT, |
| confidence=0.85, |
| ensemble_disagreement=0.12, |
| features={...}, |
| physics_override=False, |
| nl_summary="...", |
| ) |
| ``` |
|
|
| **Used by multiple Phase 2 components:** |
| - **BeliefUpdater:** Uses `label` and `confidence` to boost particle weights; `physics_override=True` → inflates uncertainty |
| - **MultiResBO:** Creates BOPoints from classifications; `confidence` becomes the reward signal |
| - **StateMachine:** Uses `confidence` to determine if stage success threshold is met |
| - **HITLManager:** Uses `ensemble_disagreement` in risk score computation |
|
|
| ### Safety Integration (Phase 0 → Phase 2) |
|
|
| **ExecutiveAgent always calls SafetyCritic before any move:** |
| ```python |
| proposal = bo.propose(...) # Phase 2 proposes |
| proposal = safety_critic.clip(proposal, current) # Phase 0 clips |
| verdict = safety_critic.verify(current, proposal) # Phase 0 verifies |
| |
| if verdict.all_passed: |
| translator.execute_voltage_move(...) # Phase 2 executes |
| state.apply_move(proposal.safe_delta_v) # Phase 0 records |
| else: |
| state.record_safety_violation() |
| ``` |
|
|
| No component can bypass SafetyCritic — it's architecturally enforced. |
|
|
| ### HITL Integration (Phase 0 → Phase 2) |
|
|
| **HITLManager is called at two points:** |
| 1. **Risk score computation (every voltage move):** |
| ```python |
| risk = hitl_manager.compute_risk_score(...) |
| if risk >= 0.70: |
| event = hitl_manager.queue_request(...) |
| event = hitl_manager.await_decision(event) # BLOCKS |
| ``` |
|
|
| 2. **State machine backtracking (condition 8):** |
| ```python |
| if state.consecutive_backtracks >= 2: |
| # StateMachine returns hitl_triggered=True |
| # ExecutiveAgent queues HITL event |
| ``` |
|
|
| **No timeout auto-approval** — agent blocks until human decides. |
|
|
| --- |
|
|
| ## Running the Integrated System |
|
|
| ### Without Trained Models (CI/Development) |
| ```bash |
| # Uses InspectionAgent in stub mode (untrained ensemble, no OOD) |
| pytest tests/test_integration_phase012.py -v |
| |
| # Run benchmark without checkpoints |
| python experiments/benchmark_phase2.py --fast --skip-missing-checkpoints |
| ``` |
|
|
| ### With Trained Models (Full System) |
| ```bash |
| # 1. Train Phase 1 models |
| python experiments/train_phase1.py --out experiments/checkpoints/phase1 |
| |
| # 2. Run benchmark |
| python experiments/benchmark_phase2.py --n-trials 100 --budget 2048 |
| ``` |
|
|
| ### Manual Inspection |
| ```python |
| from qdot.core.state import ExperimentState |
| from qdot.simulator.cim import CIMSimulatorAdapter |
| from qdot.agent.executive import ExecutiveAgent |
| from qdot.perception.inspector import InspectionAgent |
| from qdot.core.hitl import HITLManager, HITLOutcome |
| |
| # Setup |
| state = ExperimentState.new(device_id="manual_test") |
| adapter = CIMSimulatorAdapter(device_id="manual_test", seed=42) |
| inspector = InspectionAgent(ensemble=None, ood_detector=None) # Or load trained |
| |
| hitl = HITLManager() |
| hitl.set_test_mode(auto_outcome=HITLOutcome.APPROVED) # No blocking for demo |
| |
| # Create agent |
| agent = ExecutiveAgent( |
| state=state, |
| adapter=adapter, |
| inspection_agent=inspector, |
| hitl_manager=hitl, |
| max_steps=50, |
| measurement_budget=2048, |
| ) |
| |
| # Run |
| summary = agent.run() |
| print(f"Success: {summary['success']}") |
| print(f"Measurements: {summary['total_measurements']}") |
| print(f"Reduction: {summary['measurement_reduction']:.1%}") |
| ``` |
|
|
| --- |
|
|
| ## File Organization |
|
|
| ``` |
| qdot/ |
| ├── core/ # Phase 0 — Foundation |
| │ ├── types.py # All canonical types |
| │ ├── state.py # ExperimentState + BeliefState stub |
| │ ├── governance.py # GovernanceLogger |
| │ └── hitl.py # HITLManager |
| │ |
| ├── hardware/ # Phase 0 — Device interface |
| │ ├── adapter.py # DeviceAdapter ABC |
| │ └── safety.py # SafetyCritic |
| │ |
| ├── simulator/ # Phase 0 — CIM simulator |
| │ └── cim.py # ConstantInteractionDevice + CIMSimulatorAdapter |
| │ |
| ├── perception/ # Phase 1 — Perception pipeline |
| │ ├── dqc.py # DQCGatekeeper |
| │ ├── inspector.py # InspectionAgent |
| │ ├── classifier.py # EnsembleCNN |
| │ ├── features.py # Physics validators |
| │ ├── ood.py # MahalanobisOOD |
| │ └── dataset.py # CIMDataset for training |
| │ |
| ├── planning/ # Phase 2 — POMDP + BO |
| │ ├── belief.py # BeliefUpdater + CIMObservationModel |
| │ ├── sensing.py # ActiveSensingPolicy |
| │ ├── bayesian_opt.py # MultiResBO + GaussianProcess |
| │ └── state_machine.py # StateMachine (5 stages) |
| │ |
| └── agent/ # Phase 2 — Main loop |
| ├── executive.py # ExecutiveAgent (orchestrator) |
| └── translator.py # TranslationAgent (NL → API) |
| ``` |
|
|
| --- |
|
|
| ## Testing Strategy |
|
|
| ### Unit Tests (per module) |
| - `tests/test_types.py` — Phase 0 types |
| - `tests/test_state.py` — ExperimentState, BeliefState stub |
| - `tests/test_safety.py` — SafetyCritic + fuzz test (5000 iterations) |
| - `tests/test_simulator.py` — CIM physics |
| - `tests/test_perception.py` — DQC, CNN, OOD, InspectionAgent |
| - `tests/test_planning.py` — Belief, sensing, BO, state machine |
| - `tests/test_agent.py` — TranslationAgent, ExecutiveAgent |
|
|
| ### Integration Tests |
| - `tests/test_integration_phase012.py` — Full pipeline smoke tests |
|
|
| ### Benchmarks |
| - `experiments/train_phase1.py --fast` — Phase 1 smoke test (CI) |
| - `experiments/benchmark_phase2.py --fast` — Phase 2 quick eval (10 trials) |
| - `experiments/benchmark_phase2.py --n-trials 100` — Full benchmark |
|
|
| --- |
|
|
| ## Next Steps (Phase 3) |
|
|
| 1. **LLM Integration (IBM Granite 3-8B-Instruct)** |
| - Replace template rationales with LLM calls |
| - ONE call per stage transition + ONE per HITL trigger |
| - Budget: ~200 tokens per call |
|
|
| 2. **Disorder Learning** |
| - OOD flag → fit device-specific disorder map |
| - Inject into CIMObservationModel.device |
| - Close sim-to-real gap |
|
|
| 3. **Meta-Learning** |
| - Learn CIM parameter priors from device family |
| - Fast adaptation to new devices |
|
|
| 4. **Hardware Validation** |
| - Integrate real Si/SiGe adapter |
| - Run on QFlow hardware testbed |
| - Validate ≥50% reduction on real devices |
|
|
| --- |
|
|
| ## Troubleshooting |
|
|
| ### "No tests collected" in test_agent.py |
| **Cause:** File didn't exist or pytest can't find it. |
| **Fix:** Ensure `tests/test_agent.py` is in the repo root `tests/` directory. |
|
|
| ### "ModuleNotFoundError: No module named 'qdot.planning'" |
| **Cause:** Phase 2 modules not in Python path. |
| **Fix:** Run `pip install -e .` from repo root to install in editable mode. |
|
|
| ### InspectionAgent predictions are random |
| **Cause:** Running without trained checkpoints (ensemble=None). |
| **Fix:** Either (a) train models with `experiments/train_phase1.py`, or (b) use `--skip-missing-checkpoints` flag for testing without models. |
|
|
| ### HITL blocks forever |
| **Cause:** HITLManager not in test mode. |
| **Fix:** Call `hitl_manager.set_test_mode(auto_outcome=HITLOutcome.APPROVED)` for non-blocking testing. |
|
|
| ### SafetyCritic rejects all moves |
| **Cause:** Voltage bounds or l1_max cap too tight. |
| **Fix:** Check `state.voltage_bounds` and `state.step_caps["l1_max"]` are reasonable for your device. |
|
|
| --- |
|
|
| **Phase 0/1/2 integration complete.** All components tested individually and end-to-end. Ready for Phase 3. |
|
|