Detector: DerivedArgumentDetector
Report (why the flagged code is CORRECT and the detector is wrong):
Llm::asParameter is the translation boundary between two independent layers: it maps Engine\Execution\ToolParameter onto Ai\Schema\ToolParameter, and src/Ai holds zero imports from Engine. Passing the engine object into the AI constructor, as the rule prescribes, would add a new Ai->Engine arrow, and moving the mapping onto the engine type would add Engine->Ai. Reading three fields of the engine parameter inside the adapter is the adapter's whole job, so the flattening belongs exactly here.
Cleanest design the reporter can conceive:
Keep the mapping in the adapter that owns both imports: a private static asParameter(EngineToolParameter) on Llm constructing the Ai value from the engine value's fields, with neither layer referencing the other. That is the flagged code as written.
⚖️ Maintainer litmus: a valid detector-report needs the flagged code to ALREADY BE the
cleanest design. If the design above differs from the flagged code at all, THAT design is
the owed fix — close this report; the fix is still owed.
Where: src/Definitions/Control/Llm.php:151
Code (src/Definitions/Control/Llm.php:151):
148
149 private static function asParameter(EngineToolParameter $parameter): AiToolParameter
150 {
→ 151 return new AiToolParameter($parameter->token, $parameter->description, $parameter->required);
152 }
153
154 /**
155 * @return array<string, string>
156 */
157 private function shape(): array
158 {
159 $shape = [];
160
161 foreach ($this->dynamicOutputs() as $socket)
162 {
163 $shape[$socket->name] = $socket->type->toToken();
164 }
165
166 return $shape;
167 }
168 }
Where: src/Ai/Schema/ToolParameter.php:5
Code (src/Ai/Schema/ToolParameter.php:5):
2
3 namespace JesseGall\Workflows\Ai\Schema;
4
→ 5 final readonly class ToolParameter
6 {
7 public function __construct(
8 public string $token,
9 public string | null $description,
10 public bool $required,
11 ) {}
12 }
Where: src/Engine/Execution/ToolParameter.php:1
Code (src/Engine/Execution/ToolParameter.php:1):
→ 1 <?php
2
3 namespace JesseGall\Workflows\Engine\Execution;
4
5 use JesseGall\Workflows\Engine\InputSocket;
6
7 final readonly class ToolParameter
8 {
9 public function __construct(
10 public string $token,
11 public string | null $description,
12 public bool $required,
13 ) {}
14
15 public static function from(InputSocket $socket): self
16 {
17 return new self($socket->type->toToken(), $socket->describes, $socket->value()->isNone());
18 }
19 }
Filed via commandments report from a consumer project.
Detector:
DerivedArgumentDetectorReport (why the flagged code is CORRECT and the detector is wrong):
Llm::asParameter is the translation boundary between two independent layers: it maps Engine\Execution\ToolParameter onto Ai\Schema\ToolParameter, and src/Ai holds zero imports from Engine. Passing the engine object into the AI constructor, as the rule prescribes, would add a new Ai->Engine arrow, and moving the mapping onto the engine type would add Engine->Ai. Reading three fields of the engine parameter inside the adapter is the adapter's whole job, so the flattening belongs exactly here.
Cleanest design the reporter can conceive:
Keep the mapping in the adapter that owns both imports: a private static asParameter(EngineToolParameter) on Llm constructing the Ai value from the engine value's fields, with neither layer referencing the other. That is the flagged code as written.
Where:
src/Definitions/Control/Llm.php:151Code (
src/Definitions/Control/Llm.php:151):Where:
src/Ai/Schema/ToolParameter.php:5Code (
src/Ai/Schema/ToolParameter.php:5):Where:
src/Engine/Execution/ToolParameter.php:1Code (
src/Engine/Execution/ToolParameter.php:1):Filed via
commandments reportfrom a consumer project.