fix(tdd-gate): recognize pest JSON reporter failures as RED

composer test / php artisan test emit machine JSON ({"result":"failed",...}); command-not-found and error REDs lack the English Failed keyword the gate looked for, so legit RED runs went unseen and prod-code edits were wrongly blocked. hasFailingTestRun now also matches the structured failure markers. TDD: +1 test; full tools suite 2004 GREEN.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Дмитрий
2026-06-02 13:35:05 +03:00
parent 3420f46a59
commit 1d2d43a6f2
3 changed files with 30 additions and 3 deletions
+3 -3
View File
@@ -1,6 +1,6 @@
# Brain Status (auto-generated)
Last updated: 2026-06-02T10:04:24.915Z
Last updated: 2026-06-02T10:14:43.123Z
| Контролёр | Состояние | Детали |
|---|---|---|
@@ -97,8 +97,8 @@ Episodes since last run: 542 / threshold: 10
| PID | Имя | CPU-время | Возраст |
|---|---|---|---|
| 10388 | Code | 3.01ч | NaNч |
| 3220 | MsMpEng | 1.13ч | 0.0ч |
| 10388 | Code | 3.05ч | 1327306.2ч |
| 3220 | MsMpEng | 1.14ч | 0.0ч |
⚠️ Проверь, не «осиротевшие» ли это процессы от завершённых Claude-сессий.
+5
View File
@@ -108,6 +108,11 @@ function hasFailingTestRun(turn) {
// Numeric: "Tests N failed | M passed" with N>0
const m = txt.match(/Tests\s+(\d+)\s+failed/);
if (m && Number(m[1]) > 0) return true;
// JSON reporter (composer test / php artisan test → pest): {"result":"failed",...}
// or {"failed":N}/{"errors":N} with N>0. command-not-found / error REDs lack the
// English "Failed" keyword above, so recognise the structured marker too.
if (/"result"\s*:\s*"failed"/.test(txt)) return true;
if (/"(?:failed|errors)"\s*:\s*[1-9]/.test(txt)) return true;
}
}
}
+22
View File
@@ -168,3 +168,25 @@ describe('enforce-tdd-gate / decide', () => {
expect(r.block).toBe(false);
});
});
describe('enforce-tdd-gate / decide — JSON pest reporter RED (composer test)', () => {
// `composer test` (php artisan test) emits machine JSON like {"result":"failed",...}.
// command-not-found / error REDs lack the English "Failed" keyword, so the gate must
// recognise the structured failure marker, else legit RED runs go unseen.
it('recognizes {"result":"failed"} JSON output as a RED run', () => {
const r = decide({
toolName: 'Write',
filePath: 'wt/app/app/Console/Commands/FooCommand.php',
transcriptEntries: [
userMsg('add backfill command'),
assistantUses([
{ id: 't1', name: 'Write', input: { file_path: 'wt/app/tests/Feature/Console/FooCommandTest.php' } },
{ id: 't2', name: 'Bash', input: { command: 'composer test -- tests/Feature/Console/FooCommandTest.php # pest' } },
]),
toolResults([{ id: 't2', content: '{"tool":"pest","result":"failed","tests":4,"passed":0,"errors":4}' }]),
],
classification: null,
});
expect(r.block).toBe(false);
});
});