11# Add v3-compatible QDMI configuration and registration
22
3+ Status: Final
4+
35This ExecPlan is a living document. The sections ` Progress ` ,
46` Surprises & Discoveries ` , ` Decision Log ` , and ` Outcomes & Retrospective ` must
57be kept up to date as work proceeds.
@@ -52,9 +54,9 @@ remove the Driver. Those breaking changes remain in the separate v4 task.
5254 target dependencies, and verified build-tree discovery.
5355- [x] (2026-07-15 16:44Z) Adapted the existing Driver to eagerly materialize the
5456 registry snapshot with per-definition failure isolation and weak
55- process-wide provider-library reuse, while preserving its public API .
57+ process-wide provider-library reuse.
5658- [x] (2026-07-15 16:58Z) Added legacy-client failure-isolation and library
57- reuse coverage, build-tree and moved-install tests, static-consumer CMake
59+ reuse coverage, build-tree manifest tests, static-consumer CMake
5860 colocation, and verified the unchanged FoMaC, Qiskit, and neutral-atom
5961 suites against the installed Python package.
6062- [x] (2026-07-15 17:02Z) Added v3-focused documentation and the #1912 changelog
@@ -70,24 +72,14 @@ remove the Driver. Those breaking changes remain in the separate v4 task.
7072 the provider DLL and validated the change with debug/release focused
7173 Driver tests plus repository-wide lint.
7274- [x] (2026-07-16 09:54Z) Addressed review feedback by rejecting the reserved
73- but unimplemented ` qdmi.device-config ` object and extending the relocation
74- fixture to load and query every moved provider through the legacy Driver.
75- - [x] (2026-07-16 10:00Z) Corrected the relocation provider-name query buffer
76- according to the QDMI size contract.
77- - [x] (2026-07-16 10:09Z) Completed a fresh full-branch cleanup pass, removing
78- duplicate validation and stale iteration wording without changing the
79- public API or relocation behavior.
80- - [x] (2026-07-16 10:50Z) Accepted review feedback that the standalone registry
81- controls had no production consumer in this stage. Made the registry and
82- definitions private Driver details, removed ` ConfigOptions ` and mutation,
83- and refocused tests on the supported file and environment contract.
84- - [x] (2026-07-16 11:40Z) Superseded that boundary with the accepted stable-ID
85- API, centralized provider target consumption, preserved legacy session
86- snapshots, regenerated Python stubs, and passed focused native and Python
87- tests.
88- - [x] (2026-07-16 12:15Z) Completed a final implementation and wording cleanup,
89- then passed generated-stub, warning-free documentation, lint, and diff
90- validation.
75+ but unimplemented ` qdmi.device-config ` object.
76+ - [x] (2026-07-16 11:40Z) Kept registry discovery private, added stable-ID
77+ registration and opening, centralized provider target consumption,
78+ preserved legacy session snapshots, regenerated Python stubs, and passed
79+ focused native and Python tests.
80+ - [x] (2026-07-16 12:15Z) Removed public definition enumeration so stored
81+ credentials cannot be disclosed, removed the over-sized relocation
82+ fixture, finalized this plan, and completed validation.
9183
9284## Surprises & Discoveries
9385
@@ -128,23 +120,20 @@ remove the Driver. Those breaking changes remain in the separate v4 task.
128120 ` LoadLibraryExW ` with ` LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR ` , while the compatible
129121 Driver uses plain ` LoadLibraryW ` for configured paths and therefore does not
130122 search beside DDSIM for its wheel-local dependencies.
131- - Observation: The original moved-install test proved only manifest path
132- resolution because it never opened the discovered libraries. Evidence:
133- ` DiscoversBuiltInsAfterInstallationIsMoved ` checked ` is_regular_file ` and
134- containment under the moved root but made no Driver or QDMI query call.
135123- Observation: ` qdmi.device-config ` was accepted as an object but its contents
136124 were never consumed. Evidence: ` parseConfiguration ` called only
137125 ` requireObject ` for that key before continuing with ` devices ` .
138- - Observation: The relocated-provider name query allocated ` nameSize - 1 `
139- writable bytes but passed ` nameSize ` to the QDMI provider. Evidence: the QDMI
140- property contract includes the trailing null byte in the reported size.
141126- Observation: No production code outside the Driver used ` DeviceRegistry ` in
142127 this compatibility branch; the direct consumers were documentation and tests.
143128 Evidence: repository-wide reference inspection found only the Driver's default
144129 construction plus test and documentation examples.
145130- Observation: Legacy client sessions retained a pointer to the Driver's mutable
146131 device vector. Evidence: copying handles at session allocation prevents later
147132 opens from changing an existing session's device view.
133+ - Observation: Returning registered definitions from the public Driver API would
134+ also return session tokens, passwords, and authentication paths. Evidence:
135+ ` DeviceDefinition::session ` contains the complete ` DeviceSessionConfig ` ;
136+ definitions therefore remain internal after registration.
148137
149138## Decision Log
150139
@@ -180,51 +169,27 @@ remove the Driver. Those breaking changes remain in the separate v4 task.
180169 this stage does not implement runtime superconducting or neutral-atom device
181170 models, so accepting the object would silently ignore user intent.
182171 Date/Author: 2026-07-16 / GPT-5 via Codex.
183- - Decision: Exercise relocated providers through ` Driver::open ` and query their
184- names in the existing relocation fixture. Rationale: this is a portable
185- end-to-end check of the legacy loader and provider ABI without introducing a
186- second installed consumer build. Date/Author: 2026-07-16 / GPT-5 via Codex.
187- - Decision: Allocate the full provider-reported name size in a ` vector<char> `
188- and verify both a nonempty first character and a trailing null byte.
189- Rationale: this follows the QDMI size contract without writing beyond the
190- buffer. Date/Author: 2026-07-16 / GPT-5 via Codex.
191- - Decision: Keep ` DeviceRegistry ` and ` DeviceDefinition ` private to the legacy
192- Driver and remove ` ConfigOptions ` from this stage. Rationale: the Driver only
193- needs default file and environment discovery, while all other direct users
194- were tests or an invented documentation example. The future ` DeviceManager `
195- can introduce the appropriate public configuration surface when PR #1901 is
196- rebased and reworked. Date/Author: 2026-07-16 / GPT-5 via Codex.
197- - Decision: Supersede the private-definition decision with a public value and
198- ` Driver::registerDevice ` plus ` Driver::open ` . Rationale: stable-ID
199- registration has a production consumer now and aligns with future manager
200- vocabulary without adding that manager. Date/Author: 2026-07-16 / GPT-5 via
201- Codex.
172+ - Decision: Keep ` DeviceRegistry ` private, expose ` DeviceDefinition ` only as an
173+ input value, and provide ` Driver::registerDevice ` plus ` Driver::open ` without
174+ public definition enumeration. Rationale: stable-ID registration aligns with
175+ the future manager vocabulary, while returning definitions would disclose
176+ stored session credentials. Date/Author: 2026-07-16 / GPT-5 via Codex.
202177- Decision: Record configured providers once in a global CMake property.
203178 Rationale: Driver dependencies, runtime copies, and rpaths consume one
204179 authoritative list. Date/Author: 2026-07-16 / GPT-5 via Codex.
205180
206181## Outcomes & Retrospective
207182
208- Draft PR #1912 now contains the independently releasable compatibility
209- foundation. It preserves the v3 client, Driver, FoMaC, Qiskit, and neutral-atom
210- surfaces while replacing central built-in enumeration with relocatable
211- manifests. Focused native suites, the installed Python package, a moved runtime
212- prefix, documentation, and lint all pass locally. The v4 PR #1901 remains
213- untouched and preserved for reconstruction after this foundation merges. The
214- first CI iteration additionally exposed a dangling structured binding and
215- platform-specific path assertions; both now have debug and release regression
216- coverage. Review follow-up strengthened the relocated install fixture from a
217- path check to an actual legacy Driver load and provider property query, and the
218- configuration parser no longer silently accepts the unimplemented
219- ` device-config ` object. A second review pass corrected the provider-name buffer
220- size. The final review iteration removed the unused standalone registry API.
221- This stage exposes configuration through files and environment variables, while
222- runtime callers use the Driver's stable-ID registration and opening methods.
223-
224- The accepted comparison follow-up exposes the definition value, replaces the
225- unstable imperative loading API with stable-ID registration and opening,
226- centralizes configured provider target consumption, and preserves existing
227- legacy session views when later devices are opened.
183+ PR #1912 contains the independently releasable configuration foundation. It
184+ preserves the v3 client, Driver, FoMaC, Qiskit, and neutral-atom surfaces while
185+ replacing central built-in enumeration with relative manifest fragments. Users
186+ can configure devices through files or environment variables and can register
187+ and open runtime devices by stable ID. The unstable imperative loader is gone.
188+ Registered definitions cannot be enumerated through the public Driver API, so
189+ stored session credentials are not exposed. Configured providers are recorded
190+ once for CMake consumers, libraries are reused across independent sessions, and
191+ legacy sessions retain the device snapshot they received at allocation. The
192+ larger v4 object-model refactor remains separate.
228193
229194## Context and Orientation
230195
@@ -291,10 +256,10 @@ device snapshot when later definitions are opened.
291256
292257Fourth, test the compatibility adapter through the unchanged client and FoMaC
293258interfaces. Add a dedicated process-level test when singleton initialization
294- must be controlled before any other test accesses ` Driver::get() ` . Extend
295- installation tests to move the install tree and open built-ins after relocation.
296- Exercise a wheel or installed Python package through ` mqt.core.fomac ` , not a new
297- module. Preserve all existing Qiskit and neutral-atom names and tests.
259+ must be controlled before any other test accesses ` Driver::get() ` . Extend the
260+ build-tree checks to verify generated manifests and provider libraries. Exercise
261+ an installed Python package through ` mqt.core.fomac ` , not a new module. Preserve
262+ all existing Qiskit and neutral-atom names and tests.
298263
299264Finally, add ` docs/qdmi/configuration.md ` , link it from the existing Driver
300265documentation, and update ` CHANGELOG.md ` and ` UPGRADING.md ` with both the new
@@ -323,8 +288,7 @@ Run the unchanged Python compatibility tests after installing the package:
323288 uv sync --inexact --no-dev --no-build-isolation-package mqt-core
324289 uv run --no-sync pytest -q test/python/fomac test/python/na/test_na_fomac.py test/python/plugins/qiskit
325290
326- Run QDMI-focused CTest selection and relocation/package tests added by this
327- task, then build documentation and lint:
291+ Run the QDMI-focused CTest selection, then build documentation and lint:
328292
329293 ctest --test-dir build/debug -R 'qdmi|QDMI|fomac|FoMaC' --output-on-failure
330294 uvx nox --non-interactive -s docs
@@ -356,11 +320,11 @@ and the client interface remain present. Existing Qiskit and neutral-atom tests
356320must run without migration edits. A search of the diff must show no deletion of
357321those public surfaces.
358322
359- Packaging acceptance requires successful discovery from the build tree, a moved
360- installation tree, the Python wheel layout, and Windows runtime layout.
361- Generated manifests and provider libraries must be beside one another and
362- contain no build or install prefix. A fully static consumer must use an explicit
363- configuration file because a portable module origin does not exist.
323+ Packaging acceptance requires successful discovery from the build tree, the
324+ Python wheel layout, and Windows runtime layout. Generated manifests and
325+ provider libraries must be beside one another and contain no build or install
326+ prefix. A fully static consumer must use an explicit configuration file because
327+ a portable module origin does not exist.
364328
365329Final acceptance requires focused native and Python tests, the QDMI CTest
366330selection, warning-free documentation, ` uvx nox -s lint ` , and ` git diff --check `
@@ -391,24 +355,10 @@ Initial history inspection showed:
391355These stable commit identifiers are evidence for reconstruction, not commits to
392356cherry-pick wholesale.
393357
394- Review follow-up validation on 2026-07-16 produced:
395-
396- DeviceRegistry.*: 16 passed, 1 relocation-fixture-only skip
397- mqt-core-qdmi-registry-relocation-test: 1 passed
398- changed-file prek hooks: passed
399-
400- Final private-registry validation on 2026-07-16 produced:
401-
402- debug focused registry and Driver selection: 22 selected, 0 failed, 1 fixture-only skip
403- release focused registry and Driver selection: 22 selected, 0 failed, 1 fixture-only skip
404- focused FoMaC and Qiskit Python tests: 186 passed
405- warning-free documentation build: passed
406- uvx nox -s lint: passed
358+ Final validation on 2026-07-16 produced:
407359
408- Stable-ID registration refinement validation on 2026-07-16 produced:
409-
410- debug focused registry and Driver selection: 25 selected, 0 failed, 1 fixture-only skip
411- release focused registry and Driver selection: 25 selected, 0 failed, 1 fixture-only skip
360+ debug registry and Driver tests: 112 passed
361+ release registry and Driver tests: 112 passed
412362 focused FoMaC, neutral-atom, and Qiskit Python tests: 280 passed
413363 generated Python stubs: passed
414364 warning-free documentation build: passed
@@ -422,10 +372,11 @@ At the end of this task, `qdmi::DeviceSessionConfig` and
422372` include/mqt-core/qdmi/driver/Driver.hpp ` . ` DeviceRegistry ` remains private and
423373returns enabled definitions in stable ID order to the Driver.
424374
425- ` qdmi::Driver ` exposes ` definitions() ` ,
426- ` registerDevice(DeviceDefinition, bool) ` , and ` open(std::string_view) ` . Every
427- QDMI client export retains its existing signature. ` MQT::CoreQDMIDriver ` ,
428- ` MQT::CoreFoMaC ` , and ` mqt.core.fomac ` remain the runtime surfaces.
375+ ` qdmi::Driver ` exposes ` registerDevice(DeviceDefinition, bool) ` and
376+ ` open(std::string_view) ` . It intentionally provides no definition getter because
377+ definitions contain session credentials. Every QDMI client export retains its
378+ existing signature. ` MQT::CoreQDMIDriver ` , ` MQT::CoreFoMaC ` , and
379+ ` mqt.core.fomac ` remain the runtime surfaces.
429380
430381The implementation depends on QDMI declarations, ` nlohmann_json ` , the vendored
431382toml++ single header, spdlog, and platform dynamic-loading APIs. The registry
@@ -437,12 +388,9 @@ plan after feasibility analysis showed that the existing v4 commits cannot be
437388split mechanically. It records the compatibility boundary, reconstruction
438389strategy, and validation required before the v4 pull request may be rebuilt.
439390
440- Revision note (2026-07-16): Recorded review-driven schema rejection for the
441- unimplemented ` device-config ` object, runtime loading coverage for moved
442- provider libraries, safe provider property buffers, and the final decision to
443- keep the registry private until the ` DeviceManager ` rework.
444-
445- Revision note (2026-07-16): Superseded the private-definition boundary after the
446- accepted comparison selected stable-ID Driver registration. Recorded centralized
447- provider consumption, legacy session snapshots, temporary Python bindings, and
448- focused validation.
391+ Revision note (2026-07-16): Finalized the plan after implementing stable-ID
392+ registration, centralized provider consumption, private registry discovery,
393+ legacy session snapshots, and temporary Python bindings. Removed public
394+ definition enumeration to avoid disclosing session credentials and removed the
395+ large moved-install fixture in favor of focused build-tree and platform CI
396+ coverage.
0 commit comments