@@ -433,7 +433,7 @@ describe('MasterOrchestrator', () => {
433433 // Temporarily make all epics on-demand to trigger the zero-division guard
434434 const originalConfig = { } ;
435435 for ( const [ num , cfg ] of Object . entries ( EPIC_CONFIG ) ) {
436- originalConfig [ num ] = cfg . onDemand ;
436+ originalConfig [ num ] = { had : 'onDemand' in cfg , value : cfg . onDemand } ;
437437 cfg . onDemand = true ;
438438 }
439439
@@ -442,9 +442,57 @@ describe('MasterOrchestrator', () => {
442442 expect ( progress ) . toBe ( 0 ) ;
443443 expect ( Number . isNaN ( progress ) ) . toBe ( false ) ;
444444 } finally {
445- // Restore original config
446- for ( const [ num , val ] of Object . entries ( originalConfig ) ) {
447- EPIC_CONFIG [ num ] . onDemand = val ;
445+ // Restore original config — delete property when it was not originally set
446+ for ( const [ num , orig ] of Object . entries ( originalConfig ) ) {
447+ if ( orig . had ) {
448+ EPIC_CONFIG [ num ] . onDemand = orig . value ;
449+ } else {
450+ delete EPIC_CONFIG [ num ] . onDemand ;
451+ }
452+ }
453+ }
454+ } ) ;
455+
456+ it ( 'should not count on-demand epics in progress calculation' , async ( ) => {
457+ await orchestrator . initialize ( ) ;
458+
459+ // Epic 5 is on-demand — completing it should not affect progress
460+ await orchestrator . executeEpic ( 5 ) ;
461+ expect ( orchestrator . getProgressPercentage ( ) ) . toBe ( 0 ) ; // 0 of 3 non-on-demand
462+
463+ await orchestrator . executeEpic ( 3 ) ;
464+ expect ( orchestrator . getProgressPercentage ( ) ) . toBe ( 33 ) ; // 1 of 3 non-on-demand
465+ } ) ;
466+
467+ it ( 'should return 0 from _calculateProgressFromState when all epics are on-demand' , async ( ) => {
468+ await orchestrator . initialize ( ) ;
469+
470+ const originalConfig = { } ;
471+ for ( const [ num , cfg ] of Object . entries ( EPIC_CONFIG ) ) {
472+ originalConfig [ num ] = { had : 'onDemand' in cfg , value : cfg . onDemand } ;
473+ cfg . onDemand = true ;
474+ }
475+
476+ try {
477+ const states = await orchestrator . listSavedStates ( ) ;
478+ // _calculateProgressFromState is private, test via getStatus or direct state
479+ // Create a mock state with completed epics
480+ const mockState = {
481+ epics : {
482+ 3 : { status : EpicStatus . COMPLETED } ,
483+ 5 : { status : EpicStatus . COMPLETED } ,
484+ } ,
485+ } ;
486+ const progress = orchestrator . _calculateProgressFromState ( mockState ) ;
487+ expect ( progress ) . toBe ( 0 ) ;
488+ expect ( Number . isNaN ( progress ) ) . toBe ( false ) ;
489+ } finally {
490+ for ( const [ num , orig ] of Object . entries ( originalConfig ) ) {
491+ if ( orig . had ) {
492+ EPIC_CONFIG [ num ] . onDemand = orig . value ;
493+ } else {
494+ delete EPIC_CONFIG [ num ] . onDemand ;
495+ }
448496 }
449497 }
450498 } ) ;
0 commit comments