1- import { runReflexion , resumeReflexion , ReflexionRunner , ReflexionConfig } from '../engine' ;
2- import { ReflexionStateV2 , Answers } from '../schema' ;
1+ import {
2+ ReflexionConfig ,
3+ ReflexionRunner ,
4+ resumeReflexion ,
5+ runReflexion ,
6+ } from '../engine' ;
7+ import { Answers , ReflexionStateV2 } from '../schema' ;
38
49function createMockRunner (
510 generateResponse = 'plan' ,
6- critiqueResponse = { passed : true , score : 9 , actionableFix : '' , gstackDiagnosis : 9 , atomicBatches : 9 , productionEthos : 9 , modernWeb : 9 } ,
11+ critiqueResponse = {
12+ passed : true ,
13+ score : 9 ,
14+ actionableFix : '' ,
15+ gstackDiagnosis : 9 ,
16+ atomicBatches : 9 ,
17+ productionEthos : 9 ,
18+ modernWeb : 9 ,
19+ } ,
720 adjudicateResponse = 'verdict' ,
8- interviewResponse : any = { runId : '123' , revision : 0 , recommendation : 'approve' , questions : [ ] } ,
21+ interviewResponse : any = {
22+ runId : '123' ,
23+ revision : 0 ,
24+ recommendation : 'approve' ,
25+ questions : [ ] ,
26+ } ,
927 usageResponse = { tokens : 10 , costUsd : 0.1 }
1028) : ReflexionRunner {
1129 return {
@@ -14,6 +32,7 @@ function createMockRunner(
1432 adjudicate : jest . fn ( ) . mockResolvedValue ( adjudicateResponse ) ,
1533 interview : jest . fn ( ) . mockResolvedValue ( interviewResponse ) ,
1634 getUsage : jest . fn ( ) . mockReturnValue ( usageResponse ) ,
35+ wasDegraded : jest . fn ( ( ) => false ) ,
1736 models : { creator : 'gemini' , critic : 'claude' , adjudicator : 'claude' } ,
1837 } ;
1938}
@@ -36,41 +55,108 @@ describe('engine v2', () => {
3655 } ) ;
3756
3857 it ( 'budget gate trips' , async ( ) => {
39- const runner = createMockRunner ( 'plan' , undefined , undefined , undefined , { tokens : 1000 , costUsd : 10 } ) ;
40- const cfg : ReflexionConfig = { brief : 'test' , mode : 'auto' , budget : { maxCostUsd : 1 } } ;
58+ const runner = createMockRunner ( 'plan' , undefined , undefined , undefined , {
59+ tokens : 1000 ,
60+ costUsd : 10 ,
61+ } ) ;
62+ const cfg : ReflexionConfig = {
63+ brief : 'test' ,
64+ mode : 'auto' ,
65+ budget : { maxCostUsd : 1 } ,
66+ } ;
4167 const res = await runReflexion ( runner , cfg ) ;
4268 expect ( res . stopReason ) . toBe ( 'budget-exceeded' ) ;
4369 expect ( runner . generate ) . not . toHaveBeenCalled ( ) ;
4470 } ) ;
4571
4672 it ( 'zero-question auto-approve' , async ( ) => {
47- const runner = createMockRunner ( 'plan' , { passed : false , score : 8 , actionableFix : 'fix' , gstackDiagnosis : 9 , atomicBatches : 9 , productionEthos : 9 , modernWeb : 9 } , 'verdict' , { runId : '1' , revision : 0 , recommendation : 'refine-plan' , questions : [ { id : '1' , target : 'plan' , ref : '## P0' , question : 'q' , why : 'w' } ] } ) ;
48- const cfg : ReflexionConfig = { brief : 'test' , mode : 'interview' , passThreshold : 8 } ;
73+ const runner = createMockRunner (
74+ 'plan' ,
75+ {
76+ passed : false ,
77+ score : 8 ,
78+ actionableFix : 'fix' ,
79+ gstackDiagnosis : 9 ,
80+ atomicBatches : 9 ,
81+ productionEthos : 9 ,
82+ modernWeb : 9 ,
83+ } ,
84+ 'verdict' ,
85+ {
86+ runId : '1' ,
87+ revision : 0 ,
88+ recommendation : 'refine-plan' ,
89+ questions : [
90+ { id : '1' , target : 'plan' , ref : '## P0' , question : 'q' , why : 'w' } ,
91+ ] ,
92+ }
93+ ) ;
94+ const cfg : ReflexionConfig = {
95+ brief : 'test' ,
96+ mode : 'interview' ,
97+ passThreshold : 8 ,
98+ } ;
4999 const res = await runReflexion ( runner , cfg ) ;
50100 expect ( res . interview ?. recommendation ) . toBe ( 'approve' ) ;
51101 expect ( res . interview ?. questions ) . toHaveLength ( 0 ) ;
52102 expect ( res . stopReason ) . toBe ( 'passed' ) ;
53103 } ) ;
54104
55105 it ( 'resume refine-plan updates params' , async ( ) => {
56- const runner = createMockRunner ( 'plan' , { passed : true , score : 9 , actionableFix : '' , gstackDiagnosis : 9 , atomicBatches : 9 , productionEthos : 9 , modernWeb : 9 } , 'verdict' , { runId : '123' , revision : 1 , recommendation : 'approve' , questions : [ ] } ) ;
106+ const runner = createMockRunner (
107+ 'plan' ,
108+ {
109+ passed : true ,
110+ score : 9 ,
111+ actionableFix : '' ,
112+ gstackDiagnosis : 9 ,
113+ atomicBatches : 9 ,
114+ productionEthos : 9 ,
115+ modernWeb : 9 ,
116+ } ,
117+ 'verdict' ,
118+ { runId : '123' , revision : 1 , recommendation : 'approve' , questions : [ ] }
119+ ) ;
57120 const state : ReflexionStateV2 = {
58121 version : 2 ,
59122 runId : '123' ,
60123 brief : 'b' ,
61124 phase : 'AWAITING_ANSWERS' ,
62125 plan : 'old plan' ,
63- critiques : [ { passed : true , score : 9 , actionableFix : '' , gstackDiagnosis : 9 , atomicBatches : 9 , productionEthos : 9 , modernWeb : 9 } ] ,
126+ critiques : [
127+ {
128+ passed : true ,
129+ score : 9 ,
130+ actionableFix : '' ,
131+ gstackDiagnosis : 9 ,
132+ atomicBatches : 9 ,
133+ productionEthos : 9 ,
134+ modernWeb : 9 ,
135+ } ,
136+ ] ,
64137 revision : 1 ,
65138 params : { passThreshold : 8 , maxRevisions : 3 } ,
66139 usage : { totalTokens : 0 , costUsd : 0 , perPhase : [ ] } ,
67140 createdAt : 'd' ,
68141 updatedAt : 'd' ,
69- interview : { runId : '123' , revision : 0 , recommendation : 'tune-loop' , questions : [ { id : 'q1' , target : 'loop' , ref : 'passThreshold' , question : '?' , why : '!' } ] }
142+ interview : {
143+ runId : '123' ,
144+ revision : 0 ,
145+ recommendation : 'tune-loop' ,
146+ questions : [
147+ {
148+ id : 'q1' ,
149+ target : 'loop' ,
150+ ref : 'passThreshold' ,
151+ question : '?' ,
152+ why : '!' ,
153+ } ,
154+ ] ,
155+ } ,
70156 } ;
71157 const answers : Answers = {
72158 runId : '123' ,
73- decisions : [ { id : 'q1' , answer : '9' } ]
159+ decisions : [ { id : 'q1' , answer : '9' } ] ,
74160 } ;
75161 const cfg : ReflexionConfig = { brief : 'b' , mode : 'auto' } ;
76162 const res = await resumeReflexion ( runner , state , answers , cfg ) ;
@@ -92,11 +178,18 @@ describe('engine v2', () => {
92178 usage : { totalTokens : 0 , costUsd : 0 , perPhase : [ ] } ,
93179 createdAt : 'd' ,
94180 updatedAt : 'd' ,
95- interview : { runId : '123' , revision : 0 , recommendation : 'refine-plan' , questions : [ { id : 'q1' , target : 'plan' , ref : '## P0' , question : '?' , why : '!' } ] }
181+ interview : {
182+ runId : '123' ,
183+ revision : 0 ,
184+ recommendation : 'refine-plan' ,
185+ questions : [
186+ { id : 'q1' , target : 'plan' , ref : '## P0' , question : '?' , why : '!' } ,
187+ ] ,
188+ } ,
96189 } ;
97190 const answers : Answers = {
98191 runId : '123' ,
99- decisions : [ { id : 'q1' , answer : 'change this' } ]
192+ decisions : [ { id : 'q1' , answer : 'change this' } ] ,
100193 } ;
101194 const cfg : ReflexionConfig = { brief : 'b' } ;
102195 const res = await resumeReflexion ( runner , state , answers , cfg ) ;
@@ -109,7 +202,11 @@ describe('engine v2', () => {
109202 load : jest . fn ( ) ,
110203 save : jest . fn ( ) . mockResolvedValue ( undefined ) ,
111204 } ;
112- const cfg : ReflexionConfig = { brief : 'test' , mode : 'auto' , stateStore : mockStore } ;
205+ const cfg : ReflexionConfig = {
206+ brief : 'test' ,
207+ mode : 'auto' ,
208+ stateStore : mockStore ,
209+ } ;
113210 await runReflexion ( runner , cfg ) ;
114211 expect ( mockStore . save ) . toHaveBeenCalled ( ) ;
115212 } ) ;
0 commit comments