@@ -2499,6 +2499,18 @@ def code_key(repo: str) -> str:
24992499 return f"{ repo } ::code"
25002500
25012501
2502+ def claim_code_project_identity (
2503+ claims : dict [str , str ],
2504+ repo : str ,
2505+ project_identity : str ,
2506+ ) -> str | None :
2507+ """Claim one canonical code project and return an existing alias, if any."""
2508+ previous = claims .get (project_identity )
2509+ if previous is None :
2510+ claims [project_identity ] = repo
2511+ return previous
2512+
2513+
25022514def no_git_key (repo : str ) -> str :
25032515 """Checkpoint key proving the .git-preserving stream saw no git metadata."""
25042516 return f"{ repo } ::no_git"
@@ -4122,13 +4134,14 @@ def parse_args(argv: list[str]) -> argparse.Namespace:
41224134 help = "Parse workers passed to index_project for the CODE half "
41234135 "(default 2; avoid multiplying --repo-workers by the old "
41244136 "index_project default of 8 clang workers)." )
4125- p .add_argument ("--code-index-timeout-s" , type = int , default = 0 ,
4126- help = "Optional fail-loud timeout for each CODE index_project "
4127- "stage. 0 disables the timeout (default)." )
4128- p .add_argument ("--code-index-stall-timeout-s" , type = int , default = 0 ,
4129- help = "Optional fail-loud CODE index_project stall watchdog: "
4130- "kill when the index log has no size/mtime progress for "
4131- "this many seconds. 0 disables the watchdog (default)." )
4137+ p .add_argument ("--code-index-timeout-s" , type = int ,
4138+ default = sr .DEFAULT_CODE_INDEX_TIMEOUT_S ,
4139+ help = "Fail-loud timeout for each CODE index_project stage "
4140+ f"(default { sr .DEFAULT_CODE_INDEX_TIMEOUT_S } s; 0 disables)." )
4141+ p .add_argument ("--code-index-stall-timeout-s" , type = int ,
4142+ default = sr .DEFAULT_CODE_INDEX_STALL_TIMEOUT_S ,
4143+ help = "Fail-loud log-heartbeat CODE index_project watchdog "
4144+ f"(default { sr .DEFAULT_CODE_INDEX_STALL_TIMEOUT_S } s; 0 disables)." )
41324145 p .add_argument ("--background-code-recompress" , action = "store_true" ,
41334146 help = "Defer code parquet zstd-max recompress to a background "
41344147 "pool so repo processing can continue after valid parquet "
@@ -4220,7 +4233,11 @@ def main(argv: list[str]) -> int:
42204233 raise SystemExit ("--max-active-repos must be >= --repo-workers" )
42214234 parse_workers = max (1 , int (args .parse_workers or 1 ))
42224235 args .parse_workers = parse_workers
4223- code_index_stall_timeout_s = int (args .code_index_stall_timeout_s or 0 )
4236+ code_index_stall_timeout_s = int (
4237+ args .code_index_stall_timeout_s
4238+ if args .code_index_stall_timeout_s is not None
4239+ else sr .DEFAULT_CODE_INDEX_STALL_TIMEOUT_S
4240+ )
42244241 source_cache_dir = Path (args .source_cache_dir ) if args .source_cache_dir else None
42254242 source_dir_roots = [Path (p ) for p in args .source_dir_root ]
42264243 if args .source_cache_only and source_cache_dir is None :
@@ -4377,6 +4394,14 @@ def _on_signal(signum, _frame):
43774394 # CONVEYOR_MANIFEST; ConcurrentManifest merges + flocks every write so they
43784395 # cannot clobber each other's resume/accounting keys (H4 fix).
43794396 manifest = ConcurrentManifest .load (CONVEYOR_MANIFEST )
4397+ submitted_code_project_identities : dict [str , str ] = {}
4398+ if args .streams == "code" and repo_list is not None :
4399+ for key in manifest .done :
4400+ if not key .endswith ("::code" ):
4401+ continue
4402+ repo_name = key [:- len ("::code" )]
4403+ project_id = sr .resolve_project_identity (repo_name , repo_list )
4404+ submitted_code_project_identities .setdefault (project_id , repo_name )
43804405 try :
43814406 manifest .bind_code_revision (revision_guard .receipt )
43824407 child_guard_path = install_code_revision_child_guard (
@@ -4564,14 +4589,44 @@ def should_process(repo: str) -> bool:
45644589 range_pool = ThreadPoolExecutor (max_workers = workers )
45654590 repo_pool = ThreadPoolExecutor (max_workers = repo_workers ) if repo_workers > 1 else None
45664591
4567- def claim_repo_once (repo : str ) -> None :
4592+ def claim_repo_once (repo : str ) -> bool :
45684593 if repo in submitted_repo_names :
45694594 raise RepoFailure (
45704595 repo ,
45714596 "duplicate_repo" ,
45724597 f"repo { repo !r} was yielded/submitted twice in one conveyor run" ,
45734598 )
45744599 submitted_repo_names .add (repo )
4600+ if args .streams != "code" or repo_list is None :
4601+ return True
4602+ try :
4603+ project_id = sr .resolve_project_identity (repo , repo_list )
4604+ except Exception as exc :
4605+ raise RepoFailure (repo , "project_identity" , str (exc )) from exc
4606+ previous = claim_code_project_identity (
4607+ submitted_code_project_identities ,
4608+ repo ,
4609+ project_id ,
4610+ )
4611+ if previous is None :
4612+ return True
4613+ info = {
4614+ "source" : "code" ,
4615+ "skipped" : True ,
4616+ "skip_reason" : "duplicate_project_identity" ,
4617+ "project_identity" : project_id ,
4618+ "canonical_repo" : previous ,
4619+ "recorded_at" : time .strftime ("%Y-%m-%dT%H:%M:%S" ),
4620+ }
4621+ with manifest_lock :
4622+ manifest .mark_done (code_key (repo ), info )
4623+ progress .emit (
4624+ "duplicate_project_identity_skipped" ,
4625+ repo = repo ,
4626+ stream = "code" ,
4627+ ** info ,
4628+ )
4629+ return False
45754630
45764631 def mark_no_git_repo (repo : str ) -> None :
45774632 info = {
@@ -4611,7 +4666,8 @@ def mark_no_git_repo(repo: str) -> None:
46114666 if hasattr (gen , "close" ):
46124667 gen .close ()
46134668 break
4614- claim_repo_once (repo )
4669+ if not claim_repo_once (repo ):
4670+ continue
46154671 revision_guard .verify (f"submit repo worker for { repo } " )
46164672 res = process_one_repo (
46174673 repo , repo_dir , lengths_code , lengths_commits , args .range_size ,
@@ -4694,7 +4750,8 @@ def drain_one_or_more(block: bool = True) -> None:
46944750 if hasattr (gen , "close" ):
46954751 gen .close ()
46964752 break
4697- claim_repo_once (repo )
4753+ if not claim_repo_once (repo ):
4754+ continue
46984755 while len (inflight ) >= max_active_repos :
46994756 drain_one_or_more (block = True )
47004757 # Worker threads mutate cumulative['valid'] under manifest_lock
0 commit comments