diff --git a/src/Workflow/GenerateIssueWorkflow.php b/src/Workflow/GenerateIssueWorkflow.php index d6ee98a..6cb315d 100644 --- a/src/Workflow/GenerateIssueWorkflow.php +++ b/src/Workflow/GenerateIssueWorkflow.php @@ -193,6 +193,12 @@ protected function criticRules(): array . "- Few steps. One step that implements and verifies is the intended shape for a small task.\n" . "- Boilerplate: namespace, strict_types, the class declaration. Rejected at save if wrong.\n\n" . "REJECT when any of these hold — and say which:\n" + . '- a step is too SIMPLE to earn its own existence. This is a judgement, not a count: read ' + . 'each step and ask "if it does this little, is it a step at all, or ceremony?". A step ' + . 'whose prompt carves out only a sliver — a lookup, a restatement, one trivial action a ' + . 'neighbour would absorb without noticing — should be FOLDED into that neighbour. A step ' + . 'must justify its own fresh context; a workflow that spends one on a triviality is badly ' + . "split. (Having FEW steps is not the fault — a lone meaty step is ideal; a thin step is);\n" . "- a step is a true placeholder: no ai()/tool() call at all;\n" . '- the class builds the change as a PHP string and writes it (str_replace/preg_replace ' . 'surgery on source, a heredoc of the new file). It cannot see or fix its own mistakes ' diff --git a/tests/Workflow/GenerateIssueWorkflowTest.php b/tests/Workflow/GenerateIssueWorkflowTest.php index 84a19c7..5d3b464 100644 --- a/tests/Workflow/GenerateIssueWorkflowTest.php +++ b/tests/Workflow/GenerateIssueWorkflowTest.php @@ -163,6 +163,29 @@ public function theSolverReviewCanRejectOnSubstanceAndSeesWhatTheAuthorSaw(): vo } } + /** + * A too-simple step is a decomposition defect the reviewer must catch — the "make meaty steps" + * rule lives in the generator prompt, which the model can ignore; the gate is the critic. It is an + * EVALUATION, not a turn count: read each step and ask whether one this small earns being a step. + */ + #[Test] + public function theSolverReviewRejectsAStepTooSimpleToJustifyItself(): void + { + $dir = self::tempDir(); + + try { + $agent = self::generate($dir, 'Issue13Solver', 'simple'); + $review = self::textOf($agent, 5); // the critic's prompt + + Assert::true(str_contains($review, 'too SIMPLE to earn its own existence')); + Assert::true(str_contains($review, 'is it a step at all, or ceremony?')); + // and the judgement is not mistaken for "too few steps" — a lone meaty step stays ideal + Assert::true(str_contains($review, 'a lone meaty step is ideal')); + } finally { + self::rmrf($dir); + } + } + /** * A chosen approach reaches the model that writes the solver, and sits BESIDE the general recipe * rather than replacing it.