@@ -52,7 +52,7 @@ def filter(self, record: logging.LogRecord) -> bool:
5252from openkb .indexer import _write_long_doc_artifacts , prepare_cloud_import
5353from openkb .locks import atomic_write_json , atomic_write_text , kb_ingest_lock , kb_read_lock
5454from openkb .log import append_log
55- from openkb .mutation import MutationSnapshot , publish_staged_tree , snapshot_paths
55+ from openkb .mutation import publish_staged_tree
5656from openkb .schema import AGENTS_MD , INDEX_SEED , PAGE_CONTENT_DIRS
5757
5858# Suppress warnings after all imports — markitdown overrides filters at import time
@@ -457,29 +457,15 @@ def _add_single_file_locked(
457457 index_result = None # populated only on the long-doc branch
458458
459459 final_raw , final_source = _final_artifact_paths (result , kb_dir )
460- try :
461- snapshot = snapshot_paths (
462- kb_dir ,
463- _snapshot_add_paths (kb_dir , doc_name , final_raw , final_source ),
464- operation = "add" ,
465- details = {
466- "file_hash" : result .file_hash ,
467- "name" : file_path .name ,
468- "doc_name" : doc_name ,
469- },
470- hardlink_dirs = {
471- kb_dir / "wiki" / "concepts" ,
472- kb_dir / "wiki" / "entities" ,
473- kb_dir / ".openkb" / "files" ,
474- },
475- )
460+
461+ def commit_body () -> None :
462+ nonlocal index_result
476463 publish_staged_tree (staging_dir , kb_dir )
477464 if final_raw is not None :
478465 result .raw_path = final_raw
479466 if final_source is not None :
480467 result .source_path = final_source
481468
482- # 3/4. Index and compile
483469 if result .is_long_doc :
484470 if result .raw_path is None :
485471 raise RuntimeError (f"Converted long document has no raw artifact: { file_path .name } " )
@@ -542,34 +528,30 @@ def _add_single_file_locked(
542528 registry .remove_by_hash (existing_hash )
543529 registry .add (result .file_hash , meta )
544530
545- snapshot .mark_committed ()
546- except Exception :
547- if snapshot is None :
548- click .echo (f" [ERROR] Failed to prepare mutation snapshot for { file_path .name } ." )
549- _cleanup_staging (staging_dir )
550- return "failed"
551- rollback_error = snapshot .rollback_best_effort ()
552- if rollback_error is None :
553- snapshot .discard_best_effort ()
554- else :
555- click .echo (
556- " [ERROR] Rollback failed; mutation journal retained for recovery: "
557- f"{ snapshot .journal_path } "
558- )
559- _cleanup_staging (staging_dir )
560- return "failed"
561- finally :
562- _cleanup_staging (staging_dir )
563-
564- try :
531+ def append_ingest_log () -> None :
565532 append_log (kb_dir / "wiki" , "ingest" , file_path .name )
566- except Exception as exc :
567- logger .warning ("Failed to append ingest log for %s: %s" , file_path .name , exc )
568- cleanup_error = snapshot .discard_best_effort ()
569- if cleanup_error is not None :
570- click .echo (
571- f" [WARN] { file_path .name } added, but mutation journal cleanup failed: { cleanup_error } "
572- )
533+
534+ from openkb .add_coordinator import AddMutationPlan , run_add_mutation
535+
536+ plan = AddMutationPlan (
537+ operation = "add" ,
538+ details = {
539+ "file_hash" : result .file_hash ,
540+ "name" : file_path .name ,
541+ "doc_name" : doc_name ,
542+ },
543+ touched_paths = _snapshot_add_paths (kb_dir , doc_name , final_raw , final_source ),
544+ body = commit_body ,
545+ post_commit_hooks = [append_ingest_log ],
546+ hardlink_dirs = {
547+ kb_dir / "wiki" / "concepts" ,
548+ kb_dir / "wiki" / "entities" ,
549+ kb_dir / ".openkb" / "files" ,
550+ },
551+ staging_dirs = [staging_dir ],
552+ )
553+ if not run_add_mutation (kb_dir , plan ):
554+ return "failed"
573555 click .echo (f" [OK] { file_path .name } added to knowledge base." )
574556 return "added"
575557
@@ -602,8 +584,9 @@ def import_from_pageindex_cloud(
602584 return "skipped"
603585
604586 click .echo (f"Importing from PageIndex Cloud: { doc_id } " )
605- snapshot : MutationSnapshot | None = None
606587 doc_name = ""
588+ from openkb .add_coordinator import AddMutationPlan , DirtyRollbackError , run_add_mutation
589+
607590 try :
608591 try :
609592 cloud = prepare_cloud_import (doc_id , kb_dir , path_key )
@@ -613,76 +596,69 @@ def import_from_pageindex_cloud(
613596 return "failed"
614597
615598 doc_name = cloud .doc_name
616- snapshot = snapshot_paths (
617- kb_dir ,
618- _snapshot_add_paths (kb_dir , doc_name , None , None ),
599+
600+ def commit_body () -> None :
601+ summary_path = _write_long_doc_artifacts (
602+ cloud .tree ,
603+ cloud .all_pages ,
604+ doc_name ,
605+ doc_id ,
606+ kb_dir ,
607+ description = cloud .description ,
608+ )
609+ _run_compile_with_retry (
610+ lambda : compile_long_doc (
611+ doc_name ,
612+ summary_path ,
613+ doc_id ,
614+ kb_dir ,
615+ model ,
616+ doc_description = cloud .description ,
617+ ),
618+ label = f"Compiling imported doc (doc_id={ doc_id } )" ,
619+ )
620+
621+ # Register the raw-less cloud entry only after successful compilation.
622+ registry = HashRegistry (openkb_dir / "hashes.json" )
623+ meta = {
624+ "name" : cloud .cloud_name ,
625+ "doc_name" : doc_name ,
626+ "type" : "pageindex_cloud" ,
627+ "origin" : "cloud" ,
628+ "path" : path_key ,
629+ "source_path" : _registry_path (
630+ kb_dir / "wiki" / "sources" / f"{ doc_name } .json" , kb_dir
631+ ),
632+ "doc_id" : doc_id ,
633+ }
634+ registry .remove_by_doc_name (doc_name )
635+ registry .add (synthetic_hash , meta )
636+
637+ def append_cloud_log () -> None :
638+ append_log (kb_dir / "wiki" , "ingest" , doc_name )
639+
640+ plan = AddMutationPlan (
619641 operation = "cloud_import" ,
620642 details = {"doc_id" : doc_id , "doc_name" : doc_name },
643+ touched_paths = _snapshot_add_paths (kb_dir , doc_name , None , None ),
644+ body = commit_body ,
645+ post_commit_hooks = [append_cloud_log ],
621646 hardlink_dirs = {
622647 kb_dir / "wiki" / "concepts" ,
623648 kb_dir / "wiki" / "entities" ,
624649 kb_dir / ".openkb" / "files" ,
625650 },
626651 )
627- summary_path = _write_long_doc_artifacts (
628- cloud .tree ,
629- cloud .all_pages ,
630- doc_name ,
631- doc_id ,
632- kb_dir ,
633- description = cloud .description ,
634- )
635- _run_compile_with_retry (
636- lambda : compile_long_doc (
637- doc_name ,
638- summary_path ,
639- doc_id ,
640- kb_dir ,
641- model ,
642- doc_description = cloud .description ,
643- ),
644- label = f"Compiling imported doc (doc_id={ doc_id } )" ,
645- )
646-
647- # Register the raw-less cloud entry only after successful compilation.
648- registry = HashRegistry (openkb_dir / "hashes.json" )
649- meta = {
650- "name" : cloud .cloud_name ,
651- "doc_name" : doc_name ,
652- "type" : "pageindex_cloud" ,
653- "origin" : "cloud" ,
654- "path" : path_key ,
655- "source_path" : _registry_path (
656- kb_dir / "wiki" / "sources" / f"{ doc_name } .json" , kb_dir
657- ),
658- "doc_id" : doc_id ,
659- }
660- registry .remove_by_doc_name (doc_name )
661- registry .add (synthetic_hash , meta )
662- snapshot .mark_committed ()
652+ with kb_ingest_lock (kb_dir / ".openkb" ):
653+ if not run_add_mutation (kb_dir , plan ):
654+ return "failed"
655+ except DirtyRollbackError :
656+ raise
663657 except Exception :
664- if snapshot is None :
665- click .echo (f" [ERROR] Failed to prepare mutation snapshot for cloud import { doc_id } ." )
666- return "failed"
667- rollback_error = snapshot .rollback_best_effort ()
668- if rollback_error is None :
669- snapshot .discard_best_effort ()
670- else :
671- click .echo (
672- " [ERROR] Rollback failed; mutation journal retained for recovery: "
673- f"{ snapshot .journal_path } "
674- )
658+ click .echo (f" [ERROR] Failed to prepare mutation snapshot for cloud import { doc_id } ." )
659+ logger .debug ("Cloud import mutation traceback:" , exc_info = True )
675660 return "failed"
676661
677- try :
678- append_log (kb_dir / "wiki" , "ingest" , doc_name )
679- except Exception as exc :
680- logger .warning ("Failed to append ingest log for cloud import %s: %s" , doc_id , exc )
681- cleanup_error = snapshot .discard_best_effort ()
682- if cleanup_error is not None :
683- click .echo (
684- f" [WARN] { doc_name } imported, but mutation journal cleanup failed: { cleanup_error } "
685- )
686662 click .echo (f" [OK] { doc_name } imported from PageIndex Cloud." )
687663 return "added"
688664
0 commit comments