agentic-qe 1.8.1 → 1.8.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/agents/qe-test-generator.md +580 -0
- package/.claude/agents/subagents/qe-code-reviewer.md +86 -0
- package/.claude/agents/subagents/qe-coverage-gap-analyzer.md +485 -0
- package/.claude/agents/subagents/qe-data-generator.md +86 -0
- package/.claude/agents/subagents/qe-flaky-investigator.md +416 -0
- package/.claude/agents/subagents/qe-integration-tester.md +87 -0
- package/.claude/agents/subagents/qe-performance-validator.md +98 -0
- package/.claude/agents/subagents/qe-security-auditor.md +86 -0
- package/.claude/agents/subagents/qe-test-data-architect-sub.md +553 -0
- package/.claude/agents/subagents/qe-test-implementer.md +229 -15
- package/.claude/agents/subagents/qe-test-refactorer.md +265 -15
- package/.claude/agents/subagents/qe-test-writer.md +180 -20
- package/CHANGELOG.md +182 -0
- package/README.md +52 -35
- package/dist/core/hooks/validators/TDDPhaseValidator.d.ts +110 -0
- package/dist/core/hooks/validators/TDDPhaseValidator.d.ts.map +1 -0
- package/dist/core/hooks/validators/TDDPhaseValidator.js +287 -0
- package/dist/core/hooks/validators/TDDPhaseValidator.js.map +1 -0
- package/dist/core/hooks/validators/index.d.ts +3 -1
- package/dist/core/hooks/validators/index.d.ts.map +1 -1
- package/dist/core/hooks/validators/index.js +4 -2
- package/dist/core/hooks/validators/index.js.map +1 -1
- package/dist/core/memory/RealAgentDBAdapter.d.ts +77 -2
- package/dist/core/memory/RealAgentDBAdapter.d.ts.map +1 -1
- package/dist/core/memory/RealAgentDBAdapter.js +259 -3
- package/dist/core/memory/RealAgentDBAdapter.js.map +1 -1
- package/package.json +1 -1
|
@@ -268,38 +268,252 @@ class IncrementalDeveloper {
|
|
|
268
268
|
}
|
|
269
269
|
```
|
|
270
270
|
|
|
271
|
+
## TDD Coordination Protocol
|
|
272
|
+
|
|
273
|
+
### Cycle-Based Memory Namespace
|
|
274
|
+
|
|
275
|
+
All TDD subagents share context through a cycle-specific namespace:
|
|
276
|
+
|
|
277
|
+
```
|
|
278
|
+
aqe/tdd/cycle-{cycleId}/
|
|
279
|
+
├── context # Shared workflow context (created by parent)
|
|
280
|
+
├── red/
|
|
281
|
+
│ ├── tests # Test file content from RED phase
|
|
282
|
+
│ └── validation # RED phase validation results
|
|
283
|
+
├── green/
|
|
284
|
+
│ ├── impl # Implementation from GREEN phase
|
|
285
|
+
│ └── validation # GREEN phase validation results
|
|
286
|
+
└── refactor/
|
|
287
|
+
├── result # Final refactored code
|
|
288
|
+
└── validation # REFACTOR phase validation results
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
### Input Protocol (from qe-test-writer)
|
|
292
|
+
|
|
293
|
+
**Required Input Structure:**
|
|
294
|
+
```typescript
|
|
295
|
+
interface REDPhaseOutput {
|
|
296
|
+
cycleId: string; // Unique identifier for this TDD cycle
|
|
297
|
+
phase: 'RED';
|
|
298
|
+
timestamp: number;
|
|
299
|
+
testFile: {
|
|
300
|
+
path: string; // Absolute path to test file
|
|
301
|
+
content: string; // Full test file content
|
|
302
|
+
hash: string; // SHA256 hash for validation
|
|
303
|
+
};
|
|
304
|
+
tests: Array<{
|
|
305
|
+
name: string; // Test description
|
|
306
|
+
type: 'unit' | 'integration' | 'e2e';
|
|
307
|
+
assertion: string; // What it asserts
|
|
308
|
+
givenWhenThen: {
|
|
309
|
+
given: string;
|
|
310
|
+
when: string;
|
|
311
|
+
then: string;
|
|
312
|
+
};
|
|
313
|
+
}>;
|
|
314
|
+
validation: {
|
|
315
|
+
allTestsFailing: boolean; // MUST be true
|
|
316
|
+
failureCount: number;
|
|
317
|
+
errorMessages: string[];
|
|
318
|
+
};
|
|
319
|
+
nextPhase: 'GREEN';
|
|
320
|
+
readyForHandoff: boolean; // MUST be true to proceed
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// Retrieve RED phase output
|
|
324
|
+
const redOutput = await this.memoryStore.retrieve(`aqe/tdd/cycle-${cycleId}/red/tests`, {
|
|
325
|
+
partition: 'coordination'
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
// Validate RED phase is complete
|
|
329
|
+
if (!redOutput.readyForHandoff || !redOutput.validation.allTestsFailing) {
|
|
330
|
+
throw new Error('Cannot proceed to GREEN phase - RED phase incomplete');
|
|
331
|
+
}
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
### Output Protocol (for qe-test-refactorer)
|
|
335
|
+
|
|
336
|
+
**Required Output Structure:**
|
|
337
|
+
```typescript
|
|
338
|
+
interface GREENPhaseOutput {
|
|
339
|
+
cycleId: string; // Must match input cycleId
|
|
340
|
+
phase: 'GREEN';
|
|
341
|
+
timestamp: number;
|
|
342
|
+
testFile: {
|
|
343
|
+
path: string; // SAME path from RED phase
|
|
344
|
+
hash: string; // SAME hash - tests unchanged
|
|
345
|
+
};
|
|
346
|
+
implFile: {
|
|
347
|
+
path: string; // Absolute path to implementation
|
|
348
|
+
content: string; // Full implementation content
|
|
349
|
+
hash: string; // SHA256 hash for validation
|
|
350
|
+
};
|
|
351
|
+
implementation: {
|
|
352
|
+
className: string; // e.g., 'UserAuthenticationService'
|
|
353
|
+
methods: Array<{
|
|
354
|
+
name: string;
|
|
355
|
+
signature: string;
|
|
356
|
+
complexity: number;
|
|
357
|
+
}>;
|
|
358
|
+
};
|
|
359
|
+
validation: {
|
|
360
|
+
allTestsPassing: boolean; // MUST be true
|
|
361
|
+
passCount: number;
|
|
362
|
+
totalCount: number;
|
|
363
|
+
coverage: number; // Line coverage percentage
|
|
364
|
+
};
|
|
365
|
+
nextPhase: 'REFACTOR';
|
|
366
|
+
readyForHandoff: boolean; // MUST be true to proceed
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
// Store GREEN phase output
|
|
370
|
+
await this.memoryStore.store(`aqe/tdd/cycle-${cycleId}/green/impl`, output, {
|
|
371
|
+
partition: 'coordination',
|
|
372
|
+
ttl: 86400
|
|
373
|
+
});
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
### Handoff Validation
|
|
377
|
+
|
|
378
|
+
Before emitting completion, validate handoff readiness:
|
|
379
|
+
|
|
380
|
+
```typescript
|
|
381
|
+
async function validateGREENHandoff(
|
|
382
|
+
output: GREENPhaseOutput,
|
|
383
|
+
redOutput: REDPhaseOutput
|
|
384
|
+
): Promise<boolean> {
|
|
385
|
+
const errors: string[] = [];
|
|
386
|
+
|
|
387
|
+
// 1. Verify cycle IDs match
|
|
388
|
+
if (output.cycleId !== redOutput.cycleId) {
|
|
389
|
+
errors.push(`Cycle ID mismatch: ${output.cycleId} !== ${redOutput.cycleId}`);
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
// 2. Verify test file unchanged
|
|
393
|
+
if (output.testFile.hash !== redOutput.testFile.hash) {
|
|
394
|
+
errors.push('Test file was modified during GREEN phase - tests must remain unchanged');
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
// 3. Verify implementation file exists
|
|
398
|
+
if (!existsSync(output.implFile.path)) {
|
|
399
|
+
errors.push(`Implementation file not found: ${output.implFile.path}`);
|
|
400
|
+
} else {
|
|
401
|
+
const actualContent = readFileSync(output.implFile.path, 'utf-8');
|
|
402
|
+
const actualHash = createHash('sha256').update(actualContent).digest('hex');
|
|
403
|
+
if (actualHash !== output.implFile.hash) {
|
|
404
|
+
errors.push(`Implementation file content mismatch: hash differs`);
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
// 4. Verify all tests are passing
|
|
409
|
+
if (!output.validation.allTestsPassing) {
|
|
410
|
+
errors.push(`GREEN phase violation: ${output.validation.totalCount - output.validation.passCount} tests still failing`);
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
// 5. Set handoff readiness
|
|
414
|
+
output.readyForHandoff = errors.length === 0;
|
|
415
|
+
|
|
416
|
+
if (errors.length > 0) {
|
|
417
|
+
console.error('GREEN phase handoff validation failed:', errors);
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
return output.readyForHandoff;
|
|
421
|
+
}
|
|
422
|
+
```
|
|
423
|
+
|
|
271
424
|
## Integration with Parent Agents
|
|
272
425
|
|
|
273
426
|
### Input from qe-test-writer
|
|
274
427
|
|
|
275
428
|
```typescript
|
|
276
|
-
//
|
|
277
|
-
const
|
|
429
|
+
// Retrieve cycle context for file paths
|
|
430
|
+
const context = await this.memoryStore.retrieve(`aqe/tdd/cycle-${cycleId}/context`, {
|
|
431
|
+
partition: 'coordination'
|
|
432
|
+
});
|
|
433
|
+
|
|
434
|
+
// Retrieve RED phase output with tests
|
|
435
|
+
const redOutput = await this.memoryStore.retrieve(`aqe/tdd/cycle-${cycleId}/red/tests`, {
|
|
278
436
|
partition: 'coordination'
|
|
279
437
|
});
|
|
280
438
|
|
|
281
|
-
//
|
|
282
|
-
if (!
|
|
439
|
+
// Validate RED phase is complete and ready for handoff
|
|
440
|
+
if (!redOutput) {
|
|
441
|
+
throw new Error(`RED phase output not found for cycle ${cycleId}`);
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
if (!redOutput.readyForHandoff) {
|
|
445
|
+
throw new Error('Cannot proceed to GREEN phase - RED phase handoff not ready');
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
if (!redOutput.validation.allTestsFailing) {
|
|
283
449
|
throw new Error('Cannot proceed to GREEN phase - tests are not failing');
|
|
284
450
|
}
|
|
451
|
+
|
|
452
|
+
// Verify test file exists and matches expected content
|
|
453
|
+
const actualTestContent = readFileSync(redOutput.testFile.path, 'utf-8');
|
|
454
|
+
const actualHash = createHash('sha256').update(actualTestContent).digest('hex');
|
|
455
|
+
if (actualHash !== redOutput.testFile.hash) {
|
|
456
|
+
throw new Error('Test file has been modified since RED phase - cannot proceed');
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
// Now implement code to make these EXACT tests pass
|
|
460
|
+
console.log(`Implementing code to pass ${redOutput.tests.length} tests from ${redOutput.testFile.path}`);
|
|
285
461
|
```
|
|
286
462
|
|
|
287
463
|
### Output to qe-test-refactorer
|
|
288
464
|
|
|
289
465
|
```typescript
|
|
290
|
-
//
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
466
|
+
// Create GREEN phase output with implementation
|
|
467
|
+
const greenOutput: GREENPhaseOutput = {
|
|
468
|
+
cycleId: redOutput.cycleId,
|
|
469
|
+
phase: 'GREEN',
|
|
470
|
+
timestamp: Date.now(),
|
|
471
|
+
testFile: {
|
|
472
|
+
path: redOutput.testFile.path, // SAME test file
|
|
473
|
+
hash: redOutput.testFile.hash // SAME hash - tests unchanged
|
|
474
|
+
},
|
|
475
|
+
implFile: {
|
|
476
|
+
path: context.implFilePath,
|
|
477
|
+
content: generatedImplementation,
|
|
478
|
+
hash: createHash('sha256').update(generatedImplementation).digest('hex')
|
|
479
|
+
},
|
|
480
|
+
implementation: {
|
|
481
|
+
className: context.module.name,
|
|
482
|
+
methods: extractedMethods.map(m => ({
|
|
483
|
+
name: m.name,
|
|
484
|
+
signature: m.signature,
|
|
485
|
+
complexity: calculateComplexity(m)
|
|
486
|
+
}))
|
|
487
|
+
},
|
|
488
|
+
validation: {
|
|
489
|
+
allTestsPassing: testResults.passed === testResults.total,
|
|
490
|
+
passCount: testResults.passed,
|
|
491
|
+
totalCount: testResults.total,
|
|
492
|
+
coverage: testResults.coverage
|
|
493
|
+
},
|
|
494
|
+
nextPhase: 'REFACTOR',
|
|
495
|
+
readyForHandoff: true
|
|
496
|
+
};
|
|
497
|
+
|
|
498
|
+
// Validate before storing
|
|
499
|
+
await validateGREENHandoff(greenOutput, redOutput);
|
|
500
|
+
|
|
501
|
+
// Store for REFACTOR phase
|
|
502
|
+
await this.memoryStore.store(`aqe/tdd/cycle-${cycleId}/green/impl`, greenOutput, {
|
|
503
|
+
partition: 'coordination',
|
|
504
|
+
ttl: 86400
|
|
505
|
+
});
|
|
506
|
+
|
|
507
|
+
// Emit completion event with cycle reference
|
|
299
508
|
this.eventBus.emit('test-implementer:completed', {
|
|
300
509
|
agentId: this.agentId,
|
|
301
|
-
|
|
302
|
-
|
|
510
|
+
cycleId: context.cycleId,
|
|
511
|
+
implementationPath: context.implFilePath,
|
|
512
|
+
testsPassing: greenOutput.validation.passCount,
|
|
513
|
+
testsTotal: greenOutput.validation.totalCount,
|
|
514
|
+
coverage: greenOutput.validation.coverage,
|
|
515
|
+
nextPhase: 'REFACTOR',
|
|
516
|
+
readyForHandoff: greenOutput.readyForHandoff
|
|
303
517
|
});
|
|
304
518
|
```
|
|
305
519
|
|
|
@@ -350,39 +350,289 @@ class ContinuousTester {
|
|
|
350
350
|
}
|
|
351
351
|
```
|
|
352
352
|
|
|
353
|
+
## TDD Coordination Protocol
|
|
354
|
+
|
|
355
|
+
### Cycle-Based Memory Namespace
|
|
356
|
+
|
|
357
|
+
All TDD subagents share context through a cycle-specific namespace:
|
|
358
|
+
|
|
359
|
+
```
|
|
360
|
+
aqe/tdd/cycle-{cycleId}/
|
|
361
|
+
├── context # Shared workflow context (created by parent)
|
|
362
|
+
├── red/
|
|
363
|
+
│ ├── tests # Test file content from RED phase
|
|
364
|
+
│ └── validation # RED phase validation results
|
|
365
|
+
├── green/
|
|
366
|
+
│ ├── impl # Implementation from GREEN phase
|
|
367
|
+
│ └── validation # GREEN phase validation results
|
|
368
|
+
└── refactor/
|
|
369
|
+
├── result # Final refactored code
|
|
370
|
+
└── validation # REFACTOR phase validation results
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
### Input Protocol (from qe-test-implementer)
|
|
374
|
+
|
|
375
|
+
**Required Input Structure:**
|
|
376
|
+
```typescript
|
|
377
|
+
interface GREENPhaseOutput {
|
|
378
|
+
cycleId: string; // Unique identifier for this TDD cycle
|
|
379
|
+
phase: 'GREEN';
|
|
380
|
+
timestamp: number;
|
|
381
|
+
testFile: {
|
|
382
|
+
path: string; // Absolute path to test file
|
|
383
|
+
hash: string; // SHA256 hash - tests unchanged
|
|
384
|
+
};
|
|
385
|
+
implFile: {
|
|
386
|
+
path: string; // Absolute path to implementation
|
|
387
|
+
content: string; // Full implementation content
|
|
388
|
+
hash: string; // SHA256 hash for validation
|
|
389
|
+
};
|
|
390
|
+
implementation: {
|
|
391
|
+
className: string;
|
|
392
|
+
methods: Array<{
|
|
393
|
+
name: string;
|
|
394
|
+
signature: string;
|
|
395
|
+
complexity: number;
|
|
396
|
+
}>;
|
|
397
|
+
};
|
|
398
|
+
validation: {
|
|
399
|
+
allTestsPassing: boolean; // MUST be true
|
|
400
|
+
passCount: number;
|
|
401
|
+
totalCount: number;
|
|
402
|
+
coverage: number;
|
|
403
|
+
};
|
|
404
|
+
nextPhase: 'REFACTOR';
|
|
405
|
+
readyForHandoff: boolean; // MUST be true to proceed
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
// Retrieve GREEN phase output
|
|
409
|
+
const greenOutput = await this.memoryStore.retrieve(`aqe/tdd/cycle-${cycleId}/green/impl`, {
|
|
410
|
+
partition: 'coordination'
|
|
411
|
+
});
|
|
412
|
+
|
|
413
|
+
// Validate GREEN phase is complete
|
|
414
|
+
if (!greenOutput.readyForHandoff || !greenOutput.validation.allTestsPassing) {
|
|
415
|
+
throw new Error('Cannot proceed to REFACTOR phase - GREEN phase incomplete');
|
|
416
|
+
}
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
### Output Protocol (Final TDD Cycle Output)
|
|
420
|
+
|
|
421
|
+
**Required Output Structure:**
|
|
422
|
+
```typescript
|
|
423
|
+
interface REFACTORPhaseOutput {
|
|
424
|
+
cycleId: string; // Must match input cycleId
|
|
425
|
+
phase: 'REFACTOR';
|
|
426
|
+
timestamp: number;
|
|
427
|
+
testFile: {
|
|
428
|
+
path: string; // SAME path from RED/GREEN phases
|
|
429
|
+
hash: string; // SAME hash - tests unchanged throughout
|
|
430
|
+
};
|
|
431
|
+
implFile: {
|
|
432
|
+
path: string; // SAME path from GREEN phase
|
|
433
|
+
content: string; // Refactored implementation content
|
|
434
|
+
hash: string; // New hash after refactoring
|
|
435
|
+
originalHash: string; // Hash from GREEN phase for comparison
|
|
436
|
+
};
|
|
437
|
+
refactoring: {
|
|
438
|
+
applied: Array<{
|
|
439
|
+
type: string; // e.g., 'extract-function', 'rename-variable'
|
|
440
|
+
description: string;
|
|
441
|
+
linesAffected: number;
|
|
442
|
+
}>;
|
|
443
|
+
metrics: {
|
|
444
|
+
complexityBefore: number;
|
|
445
|
+
complexityAfter: number;
|
|
446
|
+
maintainabilityBefore: number;
|
|
447
|
+
maintainabilityAfter: number;
|
|
448
|
+
duplicateCodeReduced: number; // Percentage
|
|
449
|
+
};
|
|
450
|
+
};
|
|
451
|
+
validation: {
|
|
452
|
+
allTestsPassing: boolean; // MUST be true - behavior unchanged
|
|
453
|
+
passCount: number;
|
|
454
|
+
totalCount: number;
|
|
455
|
+
coverage: number; // Should be same or better
|
|
456
|
+
};
|
|
457
|
+
cycleComplete: boolean; // MUST be true
|
|
458
|
+
readyForReview: boolean; // MUST be true to proceed
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
// Store REFACTOR phase output
|
|
462
|
+
await this.memoryStore.store(`aqe/tdd/cycle-${cycleId}/refactor/result`, output, {
|
|
463
|
+
partition: 'coordination',
|
|
464
|
+
ttl: 86400
|
|
465
|
+
});
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
### Handoff Validation
|
|
469
|
+
|
|
470
|
+
Before emitting completion, validate REFACTOR phase:
|
|
471
|
+
|
|
472
|
+
```typescript
|
|
473
|
+
async function validateREFACTORHandoff(
|
|
474
|
+
output: REFACTORPhaseOutput,
|
|
475
|
+
greenOutput: GREENPhaseOutput,
|
|
476
|
+
redOutput: REDPhaseOutput
|
|
477
|
+
): Promise<boolean> {
|
|
478
|
+
const errors: string[] = [];
|
|
479
|
+
|
|
480
|
+
// 1. Verify cycle IDs match throughout
|
|
481
|
+
if (output.cycleId !== greenOutput.cycleId || output.cycleId !== redOutput.cycleId) {
|
|
482
|
+
errors.push(`Cycle ID mismatch across phases`);
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
// 2. Verify test file unchanged throughout TDD cycle
|
|
486
|
+
if (output.testFile.hash !== redOutput.testFile.hash) {
|
|
487
|
+
errors.push('Test file was modified during TDD cycle - tests must remain unchanged');
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
// 3. Verify implementation file path is same
|
|
491
|
+
if (output.implFile.path !== greenOutput.implFile.path) {
|
|
492
|
+
errors.push('Implementation file path changed during REFACTOR phase');
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
// 4. Verify implementation file exists with new content
|
|
496
|
+
if (!existsSync(output.implFile.path)) {
|
|
497
|
+
errors.push(`Implementation file not found: ${output.implFile.path}`);
|
|
498
|
+
} else {
|
|
499
|
+
const actualContent = readFileSync(output.implFile.path, 'utf-8');
|
|
500
|
+
const actualHash = createHash('sha256').update(actualContent).digest('hex');
|
|
501
|
+
if (actualHash !== output.implFile.hash) {
|
|
502
|
+
errors.push(`Implementation file content mismatch: hash differs`);
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
// 5. Verify all tests still pass (behavior unchanged)
|
|
507
|
+
if (!output.validation.allTestsPassing) {
|
|
508
|
+
errors.push(`REFACTOR phase violation: ${output.validation.totalCount - output.validation.passCount} tests now failing`);
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
// 6. Verify coverage didn't decrease
|
|
512
|
+
if (output.validation.coverage < greenOutput.validation.coverage - 0.01) {
|
|
513
|
+
errors.push(`Coverage decreased: ${greenOutput.validation.coverage} -> ${output.validation.coverage}`);
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
// 7. Set completion status
|
|
517
|
+
output.cycleComplete = errors.length === 0;
|
|
518
|
+
output.readyForReview = errors.length === 0;
|
|
519
|
+
|
|
520
|
+
if (errors.length > 0) {
|
|
521
|
+
console.error('REFACTOR phase validation failed:', errors);
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
return output.readyForReview;
|
|
525
|
+
}
|
|
526
|
+
```
|
|
527
|
+
|
|
353
528
|
## Integration with Parent Agents
|
|
354
529
|
|
|
355
530
|
### Input from qe-test-implementer
|
|
356
531
|
|
|
357
532
|
```typescript
|
|
358
|
-
//
|
|
359
|
-
const
|
|
533
|
+
// Retrieve cycle context
|
|
534
|
+
const context = await this.memoryStore.retrieve(`aqe/tdd/cycle-${cycleId}/context`, {
|
|
360
535
|
partition: 'coordination'
|
|
361
536
|
});
|
|
362
537
|
|
|
363
|
-
//
|
|
364
|
-
|
|
365
|
-
|
|
538
|
+
// Retrieve RED phase output (need test file reference)
|
|
539
|
+
const redOutput = await this.memoryStore.retrieve(`aqe/tdd/cycle-${cycleId}/red/tests`, {
|
|
540
|
+
partition: 'coordination'
|
|
541
|
+
});
|
|
542
|
+
|
|
543
|
+
// Retrieve GREEN phase output with implementation
|
|
544
|
+
const greenOutput = await this.memoryStore.retrieve(`aqe/tdd/cycle-${cycleId}/green/impl`, {
|
|
545
|
+
partition: 'coordination'
|
|
546
|
+
});
|
|
547
|
+
|
|
548
|
+
// Validate GREEN phase is complete and ready for handoff
|
|
549
|
+
if (!greenOutput) {
|
|
550
|
+
throw new Error(`GREEN phase output not found for cycle ${cycleId}`);
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
if (!greenOutput.readyForHandoff) {
|
|
554
|
+
throw new Error('Cannot proceed to REFACTOR phase - GREEN phase handoff not ready');
|
|
366
555
|
}
|
|
556
|
+
|
|
557
|
+
if (!greenOutput.validation.allTestsPassing) {
|
|
558
|
+
throw new Error('Cannot refactor - GREEN phase tests not passing');
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
// Verify implementation file exists and matches expected content
|
|
562
|
+
const actualImplContent = readFileSync(greenOutput.implFile.path, 'utf-8');
|
|
563
|
+
const actualHash = createHash('sha256').update(actualImplContent).digest('hex');
|
|
564
|
+
if (actualHash !== greenOutput.implFile.hash) {
|
|
565
|
+
throw new Error('Implementation file has been modified since GREEN phase - cannot proceed');
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
// Now refactor this EXACT code while keeping tests passing
|
|
569
|
+
console.log(`Refactoring ${greenOutput.implFile.path} while keeping ${redOutput.tests.length} tests passing`);
|
|
367
570
|
```
|
|
368
571
|
|
|
369
572
|
### Output to qe-code-reviewer
|
|
370
573
|
|
|
371
574
|
```typescript
|
|
372
|
-
//
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
575
|
+
// Create REFACTOR phase output with improved code
|
|
576
|
+
const refactorOutput: REFACTORPhaseOutput = {
|
|
577
|
+
cycleId: greenOutput.cycleId,
|
|
578
|
+
phase: 'REFACTOR',
|
|
579
|
+
timestamp: Date.now(),
|
|
580
|
+
testFile: {
|
|
581
|
+
path: redOutput.testFile.path, // SAME test file throughout
|
|
582
|
+
hash: redOutput.testFile.hash // SAME hash - tests unchanged
|
|
583
|
+
},
|
|
584
|
+
implFile: {
|
|
585
|
+
path: greenOutput.implFile.path, // SAME implementation path
|
|
586
|
+
content: refactoredCode,
|
|
587
|
+
hash: createHash('sha256').update(refactoredCode).digest('hex'),
|
|
588
|
+
originalHash: greenOutput.implFile.hash // Track what we started with
|
|
589
|
+
},
|
|
590
|
+
refactoring: {
|
|
591
|
+
applied: appliedRefactorings.map(r => ({
|
|
592
|
+
type: r.type,
|
|
593
|
+
description: r.description,
|
|
594
|
+
linesAffected: r.linesAffected
|
|
595
|
+
})),
|
|
596
|
+
metrics: {
|
|
597
|
+
complexityBefore: calculateComplexity(greenOutput.implFile.content),
|
|
598
|
+
complexityAfter: calculateComplexity(refactoredCode),
|
|
599
|
+
maintainabilityBefore: calculateMaintainability(greenOutput.implFile.content),
|
|
600
|
+
maintainabilityAfter: calculateMaintainability(refactoredCode),
|
|
601
|
+
duplicateCodeReduced: calculateDuplicateReduction(greenOutput.implFile.content, refactoredCode)
|
|
602
|
+
}
|
|
603
|
+
},
|
|
604
|
+
validation: {
|
|
605
|
+
allTestsPassing: testResults.passed === testResults.total,
|
|
606
|
+
passCount: testResults.passed,
|
|
607
|
+
totalCount: testResults.total,
|
|
608
|
+
coverage: testResults.coverage
|
|
609
|
+
},
|
|
610
|
+
cycleComplete: true,
|
|
378
611
|
readyForReview: true
|
|
379
|
-
}
|
|
612
|
+
};
|
|
613
|
+
|
|
614
|
+
// Validate before storing
|
|
615
|
+
await validateREFACTORHandoff(refactorOutput, greenOutput, redOutput);
|
|
616
|
+
|
|
617
|
+
// Store final TDD cycle result
|
|
618
|
+
await this.memoryStore.store(`aqe/tdd/cycle-${cycleId}/refactor/result`, refactorOutput, {
|
|
619
|
+
partition: 'coordination',
|
|
620
|
+
ttl: 86400
|
|
621
|
+
});
|
|
380
622
|
|
|
381
|
-
// Emit completion event
|
|
623
|
+
// Emit completion event with full cycle summary
|
|
382
624
|
this.eventBus.emit('test-refactorer:completed', {
|
|
383
625
|
agentId: this.agentId,
|
|
384
|
-
|
|
385
|
-
|
|
626
|
+
cycleId: context.cycleId,
|
|
627
|
+
testFilePath: redOutput.testFile.path,
|
|
628
|
+
implFilePath: greenOutput.implFile.path,
|
|
629
|
+
refactoringsApplied: refactorOutput.refactoring.applied.length,
|
|
630
|
+
complexityReduction: refactorOutput.refactoring.metrics.complexityBefore -
|
|
631
|
+
refactorOutput.refactoring.metrics.complexityAfter,
|
|
632
|
+
testsStillPassing: refactorOutput.validation.allTestsPassing,
|
|
633
|
+
coverage: refactorOutput.validation.coverage,
|
|
634
|
+
cycleComplete: refactorOutput.cycleComplete,
|
|
635
|
+
readyForReview: refactorOutput.readyForReview
|
|
386
636
|
});
|
|
387
637
|
```
|
|
388
638
|
|