@@ -461,13 +461,35 @@ class FakeReconcileMetadataAbility
461461 {
462462 public array $ last_input = array ();
463463 public array $ inputs = array ();
464+ public ?int $ stall_at_offset = null ;
464465
465466 public function execute ( array $ input ): array
466467 {
467468 $ this ->last_input = $ input ;
468469 $ this ->inputs [] = $ input ;
469470 $ limit = (int ) ( $ input ['limit ' ] ?? 25 );
470471 $ offset = (int ) ( $ input ['offset ' ] ?? 0 );
472+ if ( null !== $ this ->stall_at_offset && $ offset === $ this ->stall_at_offset ) {
473+ return array (
474+ 'success ' => true ,
475+ 'mode ' => 'metadata_reconcile ' ,
476+ 'dry_run ' => ! empty ($ input ['dry_run ' ]),
477+ 'summary ' => array (
478+ 'inspected ' => 0 ,
479+ 'proposed ' => 0 ,
480+ 'written ' => 0 ,
481+ ),
482+ 'pagination ' => array (
483+ 'total ' => $ offset + $ limit ,
484+ 'offset ' => $ offset ,
485+ 'limit ' => $ limit ,
486+ 'scanned ' => 0 ,
487+ 'partial ' => true ,
488+ 'complete ' => false ,
489+ 'next_offset ' => $ offset ,
490+ ),
491+ );
492+ }
471493 return array (
472494 'success ' => true ,
473495 'mode ' => 'metadata_reconcile ' ,
@@ -1100,6 +1122,17 @@ public function execute( array $input ): array
11001122 datamachine_code_cleanup_assert ($ reconcile_call_count === count ($ reconcile_metadata_ability ->inputs ), 'abandoned resume skips completed reconciliation stage ' );
11011123 datamachine_code_cleanup_assert (7 === (int ) ( $ active_finalized_ability ->last_input ['offset ' ] ?? -1 ), 'abandoned resume forwards offset to requested classifier stage ' );
11021124
1125+ $ reconcile_metadata_ability ->stall_at_offset = 90 ;
1126+ WP_CLI ::$ logs = array ();
1127+ WP_CLI ::$ successes = array ();
1128+ $ command ->worktree (array ( 'abandoned ' ), array ( 'apply ' => true , 'stage ' => 'reconcile ' , 'offset ' => 90 , 'limit ' => 10 , 'passes ' => 1 , 'until-budget ' => '30s ' , 'format ' => 'json ' ));
1129+ $ abandoned_reconcile_resume_json = json_decode (WP_CLI ::$ logs [0 ] ?? '' , true );
1130+ datamachine_code_cleanup_assert (JSON_ERROR_NONE === json_last_error (), 'abandoned same-offset reconcile continuation JSON output parses cleanly ' );
1131+ datamachine_code_cleanup_assert ('reconcile ' === ( $ abandoned_reconcile_resume_json ['continuation ' ]['stage ' ] ?? '' ), 'abandoned same-offset reconcile continuation keeps reconcile stage ' );
1132+ datamachine_code_cleanup_assert (90 === (int ) ( $ abandoned_reconcile_resume_json ['continuation ' ]['offset ' ] ?? -1 ), 'abandoned same-offset reconcile continuation keeps current offset ' );
1133+ datamachine_code_cleanup_assert (str_contains ($ abandoned_reconcile_resume_json ['continuation ' ]['next_command ' ] ?? '' , '--stage=reconcile --offset=90 ' ), 'abandoned same-offset reconcile continuation emits resumed command ' );
1134+ $ reconcile_metadata_ability ->stall_at_offset = null ;
1135+
11031136 $ prune_calls_before_preview = $ prune_ability ->calls ;
11041137 WP_CLI ::$ logs = array ();
11051138 WP_CLI ::$ successes = array ();
0 commit comments