@@ -487,14 +487,22 @@ fn normalize_rel(base_dir: &str, rel: &str) -> String {
487487/// Scan → extract symbols + call sites (tree-sitter) → rebuild graph
488488/// (caller_count, coreness, is_hub). Everything is one transaction so the graph
489489/// is never observed half-built.
490- pub fn run_indexing_pipeline ( conn : & mut Connection , project_root : & Path ) -> rusqlite:: Result < ( ) > {
490+ pub fn run_indexing_pipeline (
491+ conn : & mut Connection ,
492+ project_root : & Path ,
493+ phase : std:: sync:: Arc < std:: sync:: RwLock < crate :: types:: IndexingPhase > > ,
494+ ) -> rusqlite:: Result < ( ) > {
495+ use crate :: types:: IndexingPhase ;
496+
491497 let config = crate :: config:: load_config ( project_root) . unwrap_or_default ( ) ;
492498 let entry_point_patterns = config. entry_points ;
493499
494500 let mut files = Vec :: new ( ) ;
495501 collect_source_files ( project_root, & mut files) ;
496502 files. sort ( ) ;
497503
504+ * phase. write ( ) . unwrap ( ) = IndexingPhase :: Parsing ;
505+
498506 let now = now_secs ( ) ;
499507 let tx = conn. transaction ( ) ?;
500508
@@ -525,8 +533,13 @@ pub fn run_indexing_pipeline(conn: &mut Connection, project_root: &Path) -> rusq
525533 ) ?;
526534 }
527535
536+ * phase. write ( ) . unwrap ( ) = IndexingPhase :: BuildingEdges ;
537+
528538 rebuild_graph ( & tx, & config. hub_threshold ) ?;
529539 tx. commit ( ) ?;
540+
541+ * phase. write ( ) . unwrap ( ) = IndexingPhase :: Ready ;
542+
530543 Ok ( ( ) )
531544}
532545
@@ -629,6 +642,34 @@ mod tests {
629642 conn. query_row ( sql, [ ] , |r| r. get ( 0 ) ) . unwrap ( )
630643 }
631644
645+ fn dummy_phase ( ) -> std:: sync:: Arc < std:: sync:: RwLock < IndexingPhase > > {
646+ std:: sync:: Arc :: new ( std:: sync:: RwLock :: new ( IndexingPhase :: Scanning ) )
647+ }
648+
649+ #[ test]
650+ fn test_phase_advances_to_ready_after_pipeline ( ) {
651+ use std:: sync:: { Arc , RwLock } ;
652+ use crate :: types:: IndexingPhase ;
653+
654+ let dir = std:: env:: temp_dir ( ) . join ( format ! ( "ci_idx_phase_{}" , std:: process:: id( ) ) ) ;
655+ let _ = std:: fs:: remove_dir_all ( & dir) ;
656+ std:: fs:: create_dir_all ( & dir) . unwrap ( ) ;
657+ std:: fs:: write ( dir. join ( "a.py" ) , "def hello():\n pass\n " ) . unwrap ( ) ;
658+
659+ let mut conn = Connection :: open_in_memory ( ) . unwrap ( ) ;
660+ init_db ( & conn) . unwrap ( ) ;
661+
662+ let phase = Arc :: new ( RwLock :: new ( IndexingPhase :: Scanning ) ) ;
663+ run_indexing_pipeline ( & mut conn, & dir, phase. clone ( ) ) . unwrap ( ) ;
664+
665+ assert_eq ! (
666+ * phase. read( ) . unwrap( ) ,
667+ IndexingPhase :: Ready ,
668+ "Phase must be Ready after pipeline completes"
669+ ) ;
670+ let _ = std:: fs:: remove_dir_all ( & dir) ;
671+ }
672+
632673 #[ test]
633674 fn test_phase_transition ( ) {
634675 let mut sm = IndexStateMachine :: new ( ) ;
@@ -643,7 +684,7 @@ mod tests {
643684 std:: fs:: create_dir_all ( & dir) . unwrap ( ) ;
644685 let mut conn = Connection :: open_in_memory ( ) . unwrap ( ) ;
645686 init_db ( & conn) . unwrap ( ) ;
646- assert ! ( run_indexing_pipeline( & mut conn, & dir) . is_ok( ) ) ;
687+ assert ! ( run_indexing_pipeline( & mut conn, & dir, dummy_phase ( ) ) . is_ok( ) ) ;
647688 let _ = std:: fs:: remove_dir_all ( & dir) ;
648689 }
649690
@@ -660,7 +701,7 @@ mod tests {
660701
661702 let mut conn = Connection :: open_in_memory ( ) . unwrap ( ) ;
662703 init_db ( & conn) . unwrap ( ) ;
663- run_indexing_pipeline ( & mut conn, & dir) . unwrap ( ) ;
704+ run_indexing_pipeline ( & mut conn, & dir, dummy_phase ( ) ) . unwrap ( ) ;
664705
665706 assert_eq ! ( count( & conn, "SELECT COUNT(*) FROM symbols" ) , 2 ) ;
666707 assert_eq ! ( count( & conn, "SELECT COUNT(*) FROM file_index" ) , 1 ) ;
@@ -700,7 +741,7 @@ mod tests {
700741
701742 let mut conn = Connection :: open_in_memory ( ) . unwrap ( ) ;
702743 init_db ( & conn) . unwrap ( ) ;
703- run_indexing_pipeline ( & mut conn, & dir) . unwrap ( ) ;
744+ run_indexing_pipeline ( & mut conn, & dir, dummy_phase ( ) ) . unwrap ( ) ;
704745
705746 assert_eq ! (
706747 count(
@@ -739,7 +780,7 @@ mod tests {
739780
740781 let mut conn_default = Connection :: open_in_memory ( ) . unwrap ( ) ;
741782 init_db ( & conn_default) . unwrap ( ) ;
742- run_indexing_pipeline ( & mut conn_default, & dir) . unwrap ( ) ;
783+ run_indexing_pipeline ( & mut conn_default, & dir, dummy_phase ( ) ) . unwrap ( ) ;
743784 assert_eq ! (
744785 count(
745786 & conn_default,
@@ -756,7 +797,7 @@ mod tests {
756797 . unwrap ( ) ;
757798 let mut conn_custom = Connection :: open_in_memory ( ) . unwrap ( ) ;
758799 init_db ( & conn_custom) . unwrap ( ) ;
759- run_indexing_pipeline ( & mut conn_custom, & dir) . unwrap ( ) ;
800+ run_indexing_pipeline ( & mut conn_custom, & dir, dummy_phase ( ) ) . unwrap ( ) ;
760801 assert_eq ! (
761802 count(
762803 & conn_custom,
@@ -783,7 +824,7 @@ mod tests {
783824
784825 let mut conn = Connection :: open_in_memory ( ) . unwrap ( ) ;
785826 init_db ( & conn) . unwrap ( ) ;
786- run_indexing_pipeline ( & mut conn, & dir) . unwrap ( ) ;
827+ run_indexing_pipeline ( & mut conn, & dir, dummy_phase ( ) ) . unwrap ( ) ;
787828
788829 // The alias is de-referenced, so the edge points at helper.
789830 assert_eq ! (
@@ -811,7 +852,7 @@ mod tests {
811852
812853 let mut conn = Connection :: open_in_memory ( ) . unwrap ( ) ;
813854 init_db ( & conn) . unwrap ( ) ;
814- run_indexing_pipeline ( & mut conn, & dir) . unwrap ( ) ;
855+ run_indexing_pipeline ( & mut conn, & dir, dummy_phase ( ) ) . unwrap ( ) ;
815856
816857 // import_edges populated and to_path resolved to the in-project file.
817858 let ( to_path, module) : ( String , String ) = conn
@@ -863,7 +904,7 @@ mod tests {
863904
864905 let mut conn = Connection :: open_in_memory ( ) . unwrap ( ) ;
865906 init_db ( & conn) . unwrap ( ) ;
866- run_indexing_pipeline ( & mut conn, & dir) . unwrap ( ) ;
907+ run_indexing_pipeline ( & mut conn, & dir, dummy_phase ( ) ) . unwrap ( ) ;
867908
868909 // Method is class-qualified.
869910 assert_eq ! (
@@ -910,7 +951,7 @@ mod tests {
910951
911952 let mut conn = Connection :: open_in_memory ( ) . unwrap ( ) ;
912953 init_db ( & conn) . unwrap ( ) ;
913- run_indexing_pipeline ( & mut conn, & dir) . unwrap ( ) ;
954+ run_indexing_pipeline ( & mut conn, & dir, dummy_phase ( ) ) . unwrap ( ) ;
914955
915956 // Go method is tagged with its receiver type as class_context.
916957 assert_eq ! (
@@ -943,7 +984,7 @@ mod tests {
943984
944985 let mut conn = Connection :: open_in_memory ( ) . unwrap ( ) ;
945986 init_db ( & conn) . unwrap ( ) ;
946- run_indexing_pipeline ( & mut conn, & dir) . unwrap ( ) ;
987+ run_indexing_pipeline ( & mut conn, & dir, dummy_phase ( ) ) . unwrap ( ) ;
947988 assert_eq ! ( count( & conn, "SELECT COUNT(*) FROM symbols" ) , 1 ) ;
948989
949990 // No change → no-op.
0 commit comments