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
|
@@ -682,6 +682,586 @@ async function iterateTDDWorkflow(spec: TestSpec, previousAttempt: TDDResult): P
|
|
|
682
682
|
}
|
|
683
683
|
```
|
|
684
684
|
|
|
685
|
+
## Complete TDD Workflow Orchestration
|
|
686
|
+
|
|
687
|
+
This section provides a complete TypeScript orchestration example demonstrating proper coordination between the three TDD subagents using memory coordination through the `aqe/tdd/cycle-{id}/*` namespace.
|
|
688
|
+
|
|
689
|
+
### Full Orchestration Example
|
|
690
|
+
|
|
691
|
+
```typescript
|
|
692
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
693
|
+
|
|
694
|
+
// Type definitions
|
|
695
|
+
interface TestSpec {
|
|
696
|
+
module: string;
|
|
697
|
+
className: string;
|
|
698
|
+
methods: string[];
|
|
699
|
+
requirements: string[];
|
|
700
|
+
framework: 'jest' | 'vitest' | 'mocha';
|
|
701
|
+
context?: string;
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
interface TDDCycleResult {
|
|
705
|
+
cycleId: string;
|
|
706
|
+
tests: string;
|
|
707
|
+
implementation: string;
|
|
708
|
+
quality: QualityMetrics;
|
|
709
|
+
phases: {
|
|
710
|
+
red: PhaseResult;
|
|
711
|
+
green: PhaseResult;
|
|
712
|
+
refactor: PhaseResult;
|
|
713
|
+
};
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
interface QualityMetrics {
|
|
717
|
+
coverage: number;
|
|
718
|
+
complexity: number;
|
|
719
|
+
maintainability: number;
|
|
720
|
+
testCount: number;
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
interface PhaseResult {
|
|
724
|
+
success: boolean;
|
|
725
|
+
duration: number;
|
|
726
|
+
artifacts: string[];
|
|
727
|
+
metrics: Record<string, number>;
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
interface RedPhaseOutput {
|
|
731
|
+
readyForHandoff: boolean;
|
|
732
|
+
allTestsFailing: boolean;
|
|
733
|
+
testFilePath: string;
|
|
734
|
+
testCount: number;
|
|
735
|
+
failureReasons: string[];
|
|
736
|
+
coverage: { expected: number };
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
interface GreenPhaseOutput {
|
|
740
|
+
readyForHandoff: boolean;
|
|
741
|
+
allTestsPassing: boolean;
|
|
742
|
+
implFilePath: string;
|
|
743
|
+
testResults: { passed: number; failed: number; total: number };
|
|
744
|
+
coverage: { actual: number };
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
interface RefactorPhaseOutput {
|
|
748
|
+
success: boolean;
|
|
749
|
+
testsStillPassing: boolean;
|
|
750
|
+
qualityMetrics: QualityMetrics;
|
|
751
|
+
improvements: {
|
|
752
|
+
complexityReduction: number;
|
|
753
|
+
maintainabilityImprovement: number;
|
|
754
|
+
refactorings: string[];
|
|
755
|
+
};
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
// Memory store interface (from AQE infrastructure)
|
|
759
|
+
interface MemoryStore {
|
|
760
|
+
store(key: string, value: any, options?: { partition?: string; ttl?: number }): Promise<void>;
|
|
761
|
+
retrieve(key: string, options?: { partition?: string }): Promise<any>;
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
// Event bus interface
|
|
765
|
+
interface EventBus {
|
|
766
|
+
emit(event: string, data: any): void;
|
|
767
|
+
on(event: string, handler: (data: any) => void): void;
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
/**
|
|
771
|
+
* Complete TDD Cycle Orchestrator
|
|
772
|
+
*
|
|
773
|
+
* Coordinates the RED-GREEN-REFACTOR cycle across specialized subagents
|
|
774
|
+
* with full memory coordination and phase validation.
|
|
775
|
+
*/
|
|
776
|
+
async function orchestrateTDDCycle(
|
|
777
|
+
spec: TestSpec,
|
|
778
|
+
memory: MemoryStore,
|
|
779
|
+
eventBus: EventBus
|
|
780
|
+
): Promise<TDDCycleResult> {
|
|
781
|
+
const cycleId = uuidv4();
|
|
782
|
+
const startTime = Date.now();
|
|
783
|
+
|
|
784
|
+
console.log(`šÆ Starting TDD cycle ${cycleId} for ${spec.module}`);
|
|
785
|
+
|
|
786
|
+
// Store initial context for all subagents
|
|
787
|
+
await memory.store(`aqe/tdd/cycle-${cycleId}/context`, {
|
|
788
|
+
cycleId,
|
|
789
|
+
targetModule: spec.module,
|
|
790
|
+
className: spec.className,
|
|
791
|
+
methods: spec.methods,
|
|
792
|
+
requirements: spec.requirements,
|
|
793
|
+
framework: spec.framework,
|
|
794
|
+
context: spec.context,
|
|
795
|
+
startTime,
|
|
796
|
+
status: 'initialized'
|
|
797
|
+
}, {
|
|
798
|
+
partition: 'coordination',
|
|
799
|
+
ttl: 86400 // 24 hours
|
|
800
|
+
});
|
|
801
|
+
|
|
802
|
+
// Emit cycle start event
|
|
803
|
+
eventBus.emit('tdd:cycle:started', {
|
|
804
|
+
cycleId,
|
|
805
|
+
module: spec.module,
|
|
806
|
+
timestamp: startTime
|
|
807
|
+
});
|
|
808
|
+
|
|
809
|
+
// āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
810
|
+
// RED PHASE - Write Failing Tests
|
|
811
|
+
// āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
812
|
+
console.log(`š Phase 1/3: RED - Writing failing tests...`);
|
|
813
|
+
|
|
814
|
+
await memory.store(`aqe/tdd/cycle-${cycleId}/status`, {
|
|
815
|
+
phase: 'red',
|
|
816
|
+
status: 'in_progress',
|
|
817
|
+
timestamp: Date.now()
|
|
818
|
+
}, { partition: 'coordination' });
|
|
819
|
+
|
|
820
|
+
eventBus.emit('tdd:phase:started', {
|
|
821
|
+
cycleId,
|
|
822
|
+
phase: 'red',
|
|
823
|
+
agent: 'qe-test-writer'
|
|
824
|
+
});
|
|
825
|
+
|
|
826
|
+
// Spawn the test writer subagent
|
|
827
|
+
// In Claude Code, this would be: Task("Write failing tests", ..., "qe-test-writer")
|
|
828
|
+
const redResult = await executeSubagent('qe-test-writer', {
|
|
829
|
+
task: 'write-failing-tests',
|
|
830
|
+
cycleId,
|
|
831
|
+
spec: {
|
|
832
|
+
className: spec.className,
|
|
833
|
+
methods: spec.methods,
|
|
834
|
+
requirements: spec.requirements,
|
|
835
|
+
context: spec.context
|
|
836
|
+
},
|
|
837
|
+
coverage: {
|
|
838
|
+
target: 95,
|
|
839
|
+
includeEdgeCases: true,
|
|
840
|
+
includeErrorPaths: true,
|
|
841
|
+
includeBoundaryValues: true
|
|
842
|
+
},
|
|
843
|
+
patterns: ['AAA', 'given-when-then'],
|
|
844
|
+
framework: spec.framework,
|
|
845
|
+
memoryKeys: {
|
|
846
|
+
input: `aqe/tdd/cycle-${cycleId}/context`,
|
|
847
|
+
output: `aqe/tdd/cycle-${cycleId}/red/tests`
|
|
848
|
+
}
|
|
849
|
+
});
|
|
850
|
+
|
|
851
|
+
// Validate RED phase output
|
|
852
|
+
const redOutput: RedPhaseOutput = await memory.retrieve(
|
|
853
|
+
`aqe/tdd/cycle-${cycleId}/red/tests`,
|
|
854
|
+
{ partition: 'coordination' }
|
|
855
|
+
);
|
|
856
|
+
|
|
857
|
+
if (!redOutput) {
|
|
858
|
+
throw new Error(`RED phase failed: No output found for cycle ${cycleId}`);
|
|
859
|
+
}
|
|
860
|
+
|
|
861
|
+
if (!redOutput.readyForHandoff) {
|
|
862
|
+
throw new Error(`RED phase incomplete: Test writer not ready for handoff`);
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
if (!redOutput.allTestsFailing) {
|
|
866
|
+
throw new Error(
|
|
867
|
+
`RED phase validation failed: Tests should fail initially. ` +
|
|
868
|
+
`Expected all tests to fail but some passed.`
|
|
869
|
+
);
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
const redDuration = Date.now() - startTime;
|
|
873
|
+
console.log(`ā
RED phase complete: ${redOutput.testCount} failing tests written`);
|
|
874
|
+
console.log(` File: ${redOutput.testFilePath}`);
|
|
875
|
+
console.log(` Duration: ${redDuration}ms`);
|
|
876
|
+
|
|
877
|
+
eventBus.emit('tdd:phase:completed', {
|
|
878
|
+
cycleId,
|
|
879
|
+
phase: 'red',
|
|
880
|
+
duration: redDuration,
|
|
881
|
+
testCount: redOutput.testCount
|
|
882
|
+
});
|
|
883
|
+
|
|
884
|
+
// āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
885
|
+
// GREEN PHASE - Implement to Pass Tests
|
|
886
|
+
// āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
887
|
+
console.log(`š Phase 2/3: GREEN - Implementing code to pass tests...`);
|
|
888
|
+
|
|
889
|
+
const greenStartTime = Date.now();
|
|
890
|
+
|
|
891
|
+
await memory.store(`aqe/tdd/cycle-${cycleId}/status`, {
|
|
892
|
+
phase: 'green',
|
|
893
|
+
status: 'in_progress',
|
|
894
|
+
timestamp: Date.now()
|
|
895
|
+
}, { partition: 'coordination' });
|
|
896
|
+
|
|
897
|
+
eventBus.emit('tdd:phase:started', {
|
|
898
|
+
cycleId,
|
|
899
|
+
phase: 'green',
|
|
900
|
+
agent: 'qe-test-implementer'
|
|
901
|
+
});
|
|
902
|
+
|
|
903
|
+
// Spawn the test implementer subagent
|
|
904
|
+
// In Claude Code, this would be: Task("Implement to pass tests", ..., "qe-test-implementer")
|
|
905
|
+
const greenResult = await executeSubagent('qe-test-implementer', {
|
|
906
|
+
task: 'implement-to-pass',
|
|
907
|
+
cycleId,
|
|
908
|
+
testFilePath: redOutput.testFilePath,
|
|
909
|
+
requirements: spec.requirements,
|
|
910
|
+
constraints: {
|
|
911
|
+
maxComplexity: 15,
|
|
912
|
+
usePatterns: ['SOLID', 'dependency-injection'],
|
|
913
|
+
minimalImplementation: true // Only write what's needed to pass
|
|
914
|
+
},
|
|
915
|
+
framework: spec.framework,
|
|
916
|
+
memoryKeys: {
|
|
917
|
+
input: `aqe/tdd/cycle-${cycleId}/red/tests`,
|
|
918
|
+
output: `aqe/tdd/cycle-${cycleId}/green/impl`
|
|
919
|
+
}
|
|
920
|
+
});
|
|
921
|
+
|
|
922
|
+
// Validate GREEN phase output
|
|
923
|
+
const greenOutput: GreenPhaseOutput = await memory.retrieve(
|
|
924
|
+
`aqe/tdd/cycle-${cycleId}/green/impl`,
|
|
925
|
+
{ partition: 'coordination' }
|
|
926
|
+
);
|
|
927
|
+
|
|
928
|
+
if (!greenOutput) {
|
|
929
|
+
throw new Error(`GREEN phase failed: No output found for cycle ${cycleId}`);
|
|
930
|
+
}
|
|
931
|
+
|
|
932
|
+
if (!greenOutput.readyForHandoff) {
|
|
933
|
+
throw new Error(`GREEN phase incomplete: Implementer not ready for handoff`);
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
if (!greenOutput.allTestsPassing) {
|
|
937
|
+
const { passed, failed, total } = greenOutput.testResults;
|
|
938
|
+
throw new Error(
|
|
939
|
+
`GREEN phase validation failed: Not all tests passing. ` +
|
|
940
|
+
`${passed}/${total} passed, ${failed} failed.`
|
|
941
|
+
);
|
|
942
|
+
}
|
|
943
|
+
|
|
944
|
+
const greenDuration = Date.now() - greenStartTime;
|
|
945
|
+
console.log(`ā
GREEN phase complete: All ${greenOutput.testResults.total} tests passing`);
|
|
946
|
+
console.log(` File: ${greenOutput.implFilePath}`);
|
|
947
|
+
console.log(` Coverage: ${greenOutput.coverage.actual}%`);
|
|
948
|
+
console.log(` Duration: ${greenDuration}ms`);
|
|
949
|
+
|
|
950
|
+
eventBus.emit('tdd:phase:completed', {
|
|
951
|
+
cycleId,
|
|
952
|
+
phase: 'green',
|
|
953
|
+
duration: greenDuration,
|
|
954
|
+
testResults: greenOutput.testResults,
|
|
955
|
+
coverage: greenOutput.coverage.actual
|
|
956
|
+
});
|
|
957
|
+
|
|
958
|
+
// āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
959
|
+
// REFACTOR PHASE - Improve Code Quality
|
|
960
|
+
// āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
961
|
+
console.log(`š§ Phase 3/3: REFACTOR - Improving code quality...`);
|
|
962
|
+
|
|
963
|
+
const refactorStartTime = Date.now();
|
|
964
|
+
|
|
965
|
+
await memory.store(`aqe/tdd/cycle-${cycleId}/status`, {
|
|
966
|
+
phase: 'refactor',
|
|
967
|
+
status: 'in_progress',
|
|
968
|
+
timestamp: Date.now()
|
|
969
|
+
}, { partition: 'coordination' });
|
|
970
|
+
|
|
971
|
+
eventBus.emit('tdd:phase:started', {
|
|
972
|
+
cycleId,
|
|
973
|
+
phase: 'refactor',
|
|
974
|
+
agent: 'qe-test-refactorer'
|
|
975
|
+
});
|
|
976
|
+
|
|
977
|
+
// Spawn the refactorer subagent
|
|
978
|
+
// In Claude Code, this would be: Task("Refactor implementation", ..., "qe-test-refactorer")
|
|
979
|
+
const refactorResult = await executeSubagent('qe-test-refactorer', {
|
|
980
|
+
task: 'refactor-with-tests-green',
|
|
981
|
+
cycleId,
|
|
982
|
+
implFilePath: greenOutput.implFilePath,
|
|
983
|
+
testFilePath: redOutput.testFilePath,
|
|
984
|
+
metrics: {
|
|
985
|
+
targetComplexity: 10,
|
|
986
|
+
targetMaintainability: 85,
|
|
987
|
+
maxMethodLength: 20,
|
|
988
|
+
maxFileLength: 300
|
|
989
|
+
},
|
|
990
|
+
refactoringPatterns: [
|
|
991
|
+
'extract-method',
|
|
992
|
+
'rename-variable',
|
|
993
|
+
'simplify-conditional',
|
|
994
|
+
'remove-duplication'
|
|
995
|
+
],
|
|
996
|
+
memoryKeys: {
|
|
997
|
+
input: `aqe/tdd/cycle-${cycleId}/green/impl`,
|
|
998
|
+
output: `aqe/tdd/cycle-${cycleId}/refactor/result`
|
|
999
|
+
}
|
|
1000
|
+
});
|
|
1001
|
+
|
|
1002
|
+
// Validate REFACTOR phase output
|
|
1003
|
+
const refactorOutput: RefactorPhaseOutput = await memory.retrieve(
|
|
1004
|
+
`aqe/tdd/cycle-${cycleId}/refactor/result`,
|
|
1005
|
+
{ partition: 'coordination' }
|
|
1006
|
+
);
|
|
1007
|
+
|
|
1008
|
+
if (!refactorOutput) {
|
|
1009
|
+
throw new Error(`REFACTOR phase failed: No output found for cycle ${cycleId}`);
|
|
1010
|
+
}
|
|
1011
|
+
|
|
1012
|
+
if (!refactorOutput.testsStillPassing) {
|
|
1013
|
+
throw new Error(
|
|
1014
|
+
`REFACTOR phase validation failed: Tests broke during refactoring. ` +
|
|
1015
|
+
`Rolling back to pre-refactor state.`
|
|
1016
|
+
);
|
|
1017
|
+
}
|
|
1018
|
+
|
|
1019
|
+
const refactorDuration = Date.now() - refactorStartTime;
|
|
1020
|
+
const totalDuration = Date.now() - startTime;
|
|
1021
|
+
|
|
1022
|
+
console.log(`ā
REFACTOR phase complete`);
|
|
1023
|
+
console.log(` Complexity reduced by: ${refactorOutput.improvements.complexityReduction}%`);
|
|
1024
|
+
console.log(` Maintainability improved by: ${refactorOutput.improvements.maintainabilityImprovement}%`);
|
|
1025
|
+
console.log(` Refactorings applied: ${refactorOutput.improvements.refactorings.join(', ')}`);
|
|
1026
|
+
console.log(` Duration: ${refactorDuration}ms`);
|
|
1027
|
+
|
|
1028
|
+
eventBus.emit('tdd:phase:completed', {
|
|
1029
|
+
cycleId,
|
|
1030
|
+
phase: 'refactor',
|
|
1031
|
+
duration: refactorDuration,
|
|
1032
|
+
improvements: refactorOutput.improvements
|
|
1033
|
+
});
|
|
1034
|
+
|
|
1035
|
+
// āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
1036
|
+
// CYCLE COMPLETE - Store Final Results
|
|
1037
|
+
// āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
1038
|
+
const result: TDDCycleResult = {
|
|
1039
|
+
cycleId,
|
|
1040
|
+
tests: redOutput.testFilePath,
|
|
1041
|
+
implementation: greenOutput.implFilePath,
|
|
1042
|
+
quality: refactorOutput.qualityMetrics,
|
|
1043
|
+
phases: {
|
|
1044
|
+
red: {
|
|
1045
|
+
success: true,
|
|
1046
|
+
duration: redDuration,
|
|
1047
|
+
artifacts: [redOutput.testFilePath],
|
|
1048
|
+
metrics: {
|
|
1049
|
+
testCount: redOutput.testCount,
|
|
1050
|
+
expectedCoverage: redOutput.coverage.expected
|
|
1051
|
+
}
|
|
1052
|
+
},
|
|
1053
|
+
green: {
|
|
1054
|
+
success: true,
|
|
1055
|
+
duration: greenDuration,
|
|
1056
|
+
artifacts: [greenOutput.implFilePath],
|
|
1057
|
+
metrics: {
|
|
1058
|
+
testsPassed: greenOutput.testResults.passed,
|
|
1059
|
+
coverage: greenOutput.coverage.actual
|
|
1060
|
+
}
|
|
1061
|
+
},
|
|
1062
|
+
refactor: {
|
|
1063
|
+
success: true,
|
|
1064
|
+
duration: refactorDuration,
|
|
1065
|
+
artifacts: [greenOutput.implFilePath], // Updated in place
|
|
1066
|
+
metrics: {
|
|
1067
|
+
complexity: refactorOutput.qualityMetrics.complexity,
|
|
1068
|
+
maintainability: refactorOutput.qualityMetrics.maintainability
|
|
1069
|
+
}
|
|
1070
|
+
}
|
|
1071
|
+
}
|
|
1072
|
+
};
|
|
1073
|
+
|
|
1074
|
+
// Store final cycle results
|
|
1075
|
+
await memory.store(`aqe/tdd/cycle-${cycleId}/result`, result, {
|
|
1076
|
+
partition: 'coordination',
|
|
1077
|
+
ttl: 604800 // 7 days
|
|
1078
|
+
});
|
|
1079
|
+
|
|
1080
|
+
// Update status to complete
|
|
1081
|
+
await memory.store(`aqe/tdd/cycle-${cycleId}/status`, {
|
|
1082
|
+
phase: 'complete',
|
|
1083
|
+
status: 'success',
|
|
1084
|
+
totalDuration,
|
|
1085
|
+
timestamp: Date.now()
|
|
1086
|
+
}, { partition: 'coordination' });
|
|
1087
|
+
|
|
1088
|
+
// Emit cycle completion event
|
|
1089
|
+
eventBus.emit('tdd:cycle:completed', {
|
|
1090
|
+
cycleId,
|
|
1091
|
+
module: spec.module,
|
|
1092
|
+
duration: totalDuration,
|
|
1093
|
+
quality: refactorOutput.qualityMetrics
|
|
1094
|
+
});
|
|
1095
|
+
|
|
1096
|
+
console.log(`\nš TDD Cycle ${cycleId} Complete!`);
|
|
1097
|
+
console.log(` Total Duration: ${totalDuration}ms`);
|
|
1098
|
+
console.log(` Test File: ${redOutput.testFilePath}`);
|
|
1099
|
+
console.log(` Implementation: ${greenOutput.implFilePath}`);
|
|
1100
|
+
console.log(` Coverage: ${refactorOutput.qualityMetrics.coverage}%`);
|
|
1101
|
+
console.log(` Complexity: ${refactorOutput.qualityMetrics.complexity}`);
|
|
1102
|
+
console.log(` Maintainability: ${refactorOutput.qualityMetrics.maintainability}`);
|
|
1103
|
+
|
|
1104
|
+
return result;
|
|
1105
|
+
}
|
|
1106
|
+
|
|
1107
|
+
// Helper function to execute subagent (placeholder for actual Task tool invocation)
|
|
1108
|
+
async function executeSubagent(agentName: string, params: any): Promise<void> {
|
|
1109
|
+
// In Claude Code, this would be replaced with:
|
|
1110
|
+
// await Task("Task description", JSON.stringify(params), agentName);
|
|
1111
|
+
|
|
1112
|
+
// The subagent reads input from memoryKeys.input and writes output to memoryKeys.output
|
|
1113
|
+
console.log(` ā Executing ${agentName}...`);
|
|
1114
|
+
}
|
|
1115
|
+
```
|
|
1116
|
+
|
|
1117
|
+
### Usage Example
|
|
1118
|
+
|
|
1119
|
+
```typescript
|
|
1120
|
+
// Example: Running a TDD cycle for a UserService
|
|
1121
|
+
async function example() {
|
|
1122
|
+
// Initialize memory and event bus (from AQE infrastructure)
|
|
1123
|
+
const memory = new MemoryStore();
|
|
1124
|
+
const eventBus = new EventBus();
|
|
1125
|
+
|
|
1126
|
+
// Define the test specification
|
|
1127
|
+
const spec: TestSpec = {
|
|
1128
|
+
module: 'src/services/UserService.ts',
|
|
1129
|
+
className: 'UserService',
|
|
1130
|
+
methods: ['createUser', 'updateUser', 'deleteUser', 'findById'],
|
|
1131
|
+
requirements: [
|
|
1132
|
+
'MUST validate email format before creating user',
|
|
1133
|
+
'MUST hash password using bcrypt with salt rounds 10',
|
|
1134
|
+
'MUST throw UserNotFoundError if user does not exist',
|
|
1135
|
+
'MUST emit UserCreated event after successful creation',
|
|
1136
|
+
'MUST support pagination for list operations'
|
|
1137
|
+
],
|
|
1138
|
+
framework: 'jest',
|
|
1139
|
+
context: 'E-commerce platform user management service'
|
|
1140
|
+
};
|
|
1141
|
+
|
|
1142
|
+
try {
|
|
1143
|
+
// Run the TDD cycle
|
|
1144
|
+
const result = await orchestrateTDDCycle(spec, memory, eventBus);
|
|
1145
|
+
|
|
1146
|
+
console.log('\nš TDD Cycle Summary:');
|
|
1147
|
+
console.log(` Tests: ${result.tests}`);
|
|
1148
|
+
console.log(` Implementation: ${result.implementation}`);
|
|
1149
|
+
console.log(` Coverage: ${result.quality.coverage}%`);
|
|
1150
|
+
console.log(` Test Count: ${result.quality.testCount}`);
|
|
1151
|
+
|
|
1152
|
+
return result;
|
|
1153
|
+
} catch (error) {
|
|
1154
|
+
console.error('TDD Cycle failed:', error.message);
|
|
1155
|
+
|
|
1156
|
+
// Retrieve cycle status for debugging
|
|
1157
|
+
const cycleId = error.message.match(/cycle (\w+)/)?.[1];
|
|
1158
|
+
if (cycleId) {
|
|
1159
|
+
const status = await memory.retrieve(
|
|
1160
|
+
`aqe/tdd/cycle-${cycleId}/status`,
|
|
1161
|
+
{ partition: 'coordination' }
|
|
1162
|
+
);
|
|
1163
|
+
console.error('Last known status:', status);
|
|
1164
|
+
}
|
|
1165
|
+
|
|
1166
|
+
throw error;
|
|
1167
|
+
}
|
|
1168
|
+
}
|
|
1169
|
+
|
|
1170
|
+
// Run the example
|
|
1171
|
+
example().catch(console.error);
|
|
1172
|
+
```
|
|
1173
|
+
|
|
1174
|
+
### Event Monitoring
|
|
1175
|
+
|
|
1176
|
+
```typescript
|
|
1177
|
+
// Monitor TDD cycle progress through events
|
|
1178
|
+
function setupTDDMonitoring(eventBus: EventBus) {
|
|
1179
|
+
// Cycle lifecycle events
|
|
1180
|
+
eventBus.on('tdd:cycle:started', (data) => {
|
|
1181
|
+
console.log(`\n${'ā'.repeat(60)}`);
|
|
1182
|
+
console.log(`š TDD Cycle Started: ${data.cycleId}`);
|
|
1183
|
+
console.log(` Module: ${data.module}`);
|
|
1184
|
+
console.log(`${'ā'.repeat(60)}\n`);
|
|
1185
|
+
});
|
|
1186
|
+
|
|
1187
|
+
eventBus.on('tdd:cycle:completed', (data) => {
|
|
1188
|
+
console.log(`\n${'ā'.repeat(60)}`);
|
|
1189
|
+
console.log(`ā
TDD Cycle Completed: ${data.cycleId}`);
|
|
1190
|
+
console.log(` Duration: ${data.duration}ms`);
|
|
1191
|
+
console.log(` Coverage: ${data.quality.coverage}%`);
|
|
1192
|
+
console.log(` Maintainability: ${data.quality.maintainability}`);
|
|
1193
|
+
console.log(`${'ā'.repeat(60)}\n`);
|
|
1194
|
+
});
|
|
1195
|
+
|
|
1196
|
+
// Phase progress events
|
|
1197
|
+
eventBus.on('tdd:phase:started', (data) => {
|
|
1198
|
+
const phaseEmoji = {
|
|
1199
|
+
red: 'š',
|
|
1200
|
+
green: 'š',
|
|
1201
|
+
refactor: 'š§'
|
|
1202
|
+
}[data.phase] || 'ā¶ļø';
|
|
1203
|
+
|
|
1204
|
+
console.log(`${phaseEmoji} ${data.phase.toUpperCase()} phase started`);
|
|
1205
|
+
console.log(` Agent: ${data.agent}`);
|
|
1206
|
+
});
|
|
1207
|
+
|
|
1208
|
+
eventBus.on('tdd:phase:completed', (data) => {
|
|
1209
|
+
const phaseEmoji = {
|
|
1210
|
+
red: 'š',
|
|
1211
|
+
green: 'š',
|
|
1212
|
+
refactor: 'š§'
|
|
1213
|
+
}[data.phase] || 'ā
';
|
|
1214
|
+
|
|
1215
|
+
console.log(`${phaseEmoji} ${data.phase.toUpperCase()} phase completed`);
|
|
1216
|
+
console.log(` Duration: ${data.duration}ms`);
|
|
1217
|
+
|
|
1218
|
+
// Phase-specific metrics
|
|
1219
|
+
if (data.phase === 'red') {
|
|
1220
|
+
console.log(` Tests written: ${data.testCount}`);
|
|
1221
|
+
} else if (data.phase === 'green') {
|
|
1222
|
+
console.log(` Tests passing: ${data.testResults.passed}/${data.testResults.total}`);
|
|
1223
|
+
console.log(` Coverage: ${data.coverage}%`);
|
|
1224
|
+
} else if (data.phase === 'refactor') {
|
|
1225
|
+
console.log(` Complexity reduction: ${data.improvements.complexityReduction}%`);
|
|
1226
|
+
}
|
|
1227
|
+
});
|
|
1228
|
+
|
|
1229
|
+
// Error handling
|
|
1230
|
+
eventBus.on('tdd:cycle:error', (data) => {
|
|
1231
|
+
console.error(`\nā TDD Cycle Error: ${data.cycleId}`);
|
|
1232
|
+
console.error(` Phase: ${data.phase}`);
|
|
1233
|
+
console.error(` Error: ${data.error}`);
|
|
1234
|
+
});
|
|
1235
|
+
}
|
|
1236
|
+
|
|
1237
|
+
// Usage
|
|
1238
|
+
const eventBus = new EventBus();
|
|
1239
|
+
setupTDDMonitoring(eventBus);
|
|
1240
|
+
```
|
|
1241
|
+
|
|
1242
|
+
### Memory Namespace Structure
|
|
1243
|
+
|
|
1244
|
+
The TDD orchestration uses a structured memory namespace for coordination:
|
|
1245
|
+
|
|
1246
|
+
```
|
|
1247
|
+
aqe/tdd/cycle-{cycleId}/
|
|
1248
|
+
āāā context # Initial test specification and context
|
|
1249
|
+
āāā status # Current cycle status and phase
|
|
1250
|
+
āāā red/
|
|
1251
|
+
ā āāā tests # Test writer output (failing tests)
|
|
1252
|
+
āāā green/
|
|
1253
|
+
ā āāā impl # Implementer output (passing implementation)
|
|
1254
|
+
āāā refactor/
|
|
1255
|
+
ā āāā result # Refactorer output (improved code)
|
|
1256
|
+
āāā result # Final cycle result with all metrics
|
|
1257
|
+
```
|
|
1258
|
+
|
|
1259
|
+
Each subagent:
|
|
1260
|
+
1. Reads from the previous phase's output key
|
|
1261
|
+
2. Writes to its designated output key
|
|
1262
|
+
3. Sets `readyForHandoff: true` when complete
|
|
1263
|
+
4. Validates its phase requirements before signaling completion
|
|
1264
|
+
|
|
685
1265
|
## Example Outputs
|
|
686
1266
|
|
|
687
1267
|
### Property-Based Test Generation
|
|
@@ -52,4 +52,90 @@ interface CodeReviewerOutput {
|
|
|
52
52
|
|
|
53
53
|
---
|
|
54
54
|
|
|
55
|
+
## TDD Coordination Protocol
|
|
56
|
+
|
|
57
|
+
### Memory Namespace
|
|
58
|
+
`aqe/review/cycle-{cycleId}/*`
|
|
59
|
+
|
|
60
|
+
### Subagent Input Interface
|
|
61
|
+
```typescript
|
|
62
|
+
interface ReviewRequest {
|
|
63
|
+
cycleId: string; // Links to parent TDD workflow
|
|
64
|
+
sourceFile: string; // Path to code being reviewed
|
|
65
|
+
testFile: string; // Path to associated tests
|
|
66
|
+
refactoringChanges?: { // From qe-test-refactorer REFACTOR phase
|
|
67
|
+
before: string;
|
|
68
|
+
after: string;
|
|
69
|
+
refactoringType: string;
|
|
70
|
+
};
|
|
71
|
+
policies: string[]; // Quality policy files to apply
|
|
72
|
+
coverageThreshold: number; // Minimum coverage required (default 95)
|
|
73
|
+
complexityLimit: number; // Max cyclomatic complexity (default 15)
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Subagent Output Interface
|
|
78
|
+
```typescript
|
|
79
|
+
interface ReviewOutput {
|
|
80
|
+
cycleId: string;
|
|
81
|
+
approved: boolean;
|
|
82
|
+
issues: {
|
|
83
|
+
severity: 'error' | 'warning' | 'info';
|
|
84
|
+
rule: string;
|
|
85
|
+
message: string;
|
|
86
|
+
location: { file: string; line: number; column: number };
|
|
87
|
+
fixable: boolean;
|
|
88
|
+
}[];
|
|
89
|
+
suggestions: {
|
|
90
|
+
type: 'performance' | 'readability' | 'maintainability';
|
|
91
|
+
description: string;
|
|
92
|
+
codeSnippet?: string;
|
|
93
|
+
}[];
|
|
94
|
+
metrics: {
|
|
95
|
+
complexity: number;
|
|
96
|
+
coverage: number;
|
|
97
|
+
security: {
|
|
98
|
+
score: number;
|
|
99
|
+
vulnerabilities: number;
|
|
100
|
+
warnings: number;
|
|
101
|
+
};
|
|
102
|
+
maintainability: number;
|
|
103
|
+
linesOfCode: number;
|
|
104
|
+
testToCodeRatio: number;
|
|
105
|
+
};
|
|
106
|
+
qualityGates: {
|
|
107
|
+
complexityPassed: boolean;
|
|
108
|
+
coveragePassed: boolean;
|
|
109
|
+
securityPassed: boolean;
|
|
110
|
+
lintingPassed: boolean;
|
|
111
|
+
};
|
|
112
|
+
readyForHandoff: boolean;
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### Memory Coordination
|
|
117
|
+
- **Read from**: `aqe/refactor/cycle-{cycleId}/results` (REFACTOR phase output)
|
|
118
|
+
- **Write to**: `aqe/review/cycle-{cycleId}/results`
|
|
119
|
+
- **Status updates**: `aqe/review/cycle-{cycleId}/status`
|
|
120
|
+
|
|
121
|
+
### Quality Gate Validation
|
|
122
|
+
```typescript
|
|
123
|
+
function validateAllGates(output: ReviewOutput): boolean {
|
|
124
|
+
const gates = output.qualityGates;
|
|
125
|
+
return gates.complexityPassed &&
|
|
126
|
+
gates.coveragePassed &&
|
|
127
|
+
gates.securityPassed &&
|
|
128
|
+
gates.lintingPassed;
|
|
129
|
+
}
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### Handoff Protocol
|
|
133
|
+
1. Read refactoring results from `aqe/refactor/cycle-{cycleId}/results`
|
|
134
|
+
2. Execute all quality checks
|
|
135
|
+
3. Write results to `aqe/review/cycle-{cycleId}/results`
|
|
136
|
+
4. Set `readyForHandoff: true` only if all quality gates pass
|
|
137
|
+
5. If any gate fails, set `approved: false` with detailed issue reports
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
55
141
|
*Code Reviewer Subagent - Quality validation and standards enforcement*
|