Summary
Driver configuration flows through the codebase as a bare array $config (the constructor-promoted protected readonly array $config in AbstractQuantumDriver), read at each use site with $this->config['key'] ?? default plus an inline, ad-hoc cast — confirmed 7 such reads across AbstractQuantumDriver and AwsBraketDriver: (int) ($this->config['entropy_qubits'] ?? 16), $this->config['max_qubits'] ?? null then later (int) $ceiling, ($this->config['synchronous_safe'] ?? true) === false, $this->config['pricing'] ?? [] (twice), $this->config['max_cost_per_run'] ?? null then later (float) $ceiling. There is no shape validation at construction time — a typo'd config key ('max_qubit' instead of 'max_qubits') fails silently by falling through to the ?? default branch, with no way to distinguish "intentionally unset" from "misspelled."
Where
src/Drivers/AbstractQuantumDriver.php:119 (requiredConfig()/assertConfigured() — presence-only check, no type validation), 144-156 (assertWithinQubitCeiling()), 351 (generateEntropy())
src/Drivers/AwsBraketDriver.php:36 (beforeExecution()), 76,121 (pricing), 113-140 (assertWithinCostCeiling())
This is the general/architectural counterpart of a concrete bug already filed separately: a non-numeric max_qubits/max_cost_per_run env value silently casts to 0 rather than failing clearly (see the linked issue on config/aether.php's uncast env() calls) — that bug is a direct symptom of config having no typed shape anywhere in the pipeline.
Refactor proposal
Introduce typed DriverConfig value object(s) — e.g. a base one for common keys (entropyQubits, maxQubits) and an AwsDriverConfig extension for region/bucket/deviceArn/pricing/maxCostPerRun — constructed once from the raw array (with is_numeric() validation raising InvalidDriverConfigException for a garbage value instead of silently casting), then passed to drivers instead of the raw array. Every $this->config['key'] ?? default + cast pair collapses to a single typed property/method access.
Severity: medium
Summary
Driver configuration flows through the codebase as a bare
array $config(the constructor-promotedprotected readonly array $configinAbstractQuantumDriver), read at each use site with$this->config['key'] ?? defaultplus an inline, ad-hoc cast — confirmed 7 such reads acrossAbstractQuantumDriverandAwsBraketDriver:(int) ($this->config['entropy_qubits'] ?? 16),$this->config['max_qubits'] ?? nullthen later(int) $ceiling,($this->config['synchronous_safe'] ?? true) === false,$this->config['pricing'] ?? [](twice),$this->config['max_cost_per_run'] ?? nullthen later(float) $ceiling. There is no shape validation at construction time — a typo'd config key ('max_qubit'instead of'max_qubits') fails silently by falling through to the?? defaultbranch, with no way to distinguish "intentionally unset" from "misspelled."Where
src/Drivers/AbstractQuantumDriver.php:119(requiredConfig()/assertConfigured()— presence-only check, no type validation),144-156(assertWithinQubitCeiling()),351(generateEntropy())src/Drivers/AwsBraketDriver.php:36(beforeExecution()),76,121(pricing),113-140(assertWithinCostCeiling())This is the general/architectural counterpart of a concrete bug already filed separately: a non-numeric
max_qubits/max_cost_per_runenv value silently casts to0rather than failing clearly (see the linked issue onconfig/aether.php's uncastenv()calls) — that bug is a direct symptom of config having no typed shape anywhere in the pipeline.Refactor proposal
Introduce typed
DriverConfigvalue object(s) — e.g. a base one for common keys (entropyQubits,maxQubits) and anAwsDriverConfigextension forregion/bucket/deviceArn/pricing/maxCostPerRun— constructed once from the raw array (withis_numeric()validation raisingInvalidDriverConfigExceptionfor a garbage value instead of silently casting), then passed to drivers instead of the raw array. Every$this->config['key'] ?? default+ cast pair collapses to a single typed property/method access.Severity: medium