fix(presegment): G2 인제스트 비활성 — Option A vs uq_documents_file_path 충돌

★실번들 검증서 발견: 자식 Document(부모 file_path 공유, Option A)가 uq_documents_file_path
UNIQUE 제약 위반 → 자식 INSERT 실패. 검증된 G1 파이프라인 보호 위해 인제스트를 직접 extract 로
원복(documents.py/file_watcher 4곳). 스키마(362~364)+presegment_worker 코드는 보존(재설계 후 재활성).
재설계 후보: 자식 file_path=unique 합성값+부모 lineage 에서 실파일 해석 / file_path NULL+bundle_source_path.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
hyungi
2026-06-18 17:07:38 +09:00
parent c3d5c33813
commit 860c5c6b0c
3 changed files with 15 additions and 10 deletions
+3 -3
View File
@@ -1167,9 +1167,9 @@ async def upload_document(
canonical.duplicate_count = (canonical.duplicate_count or 0) + 1
# document + processing_queue 는 단일 트랜잭션으로 묶어 원자적 정리.
# G2 (PR-G2-2): 첫 stage = presegment (extract 前). 非PDF/단일문서는 presegment
# 변경 없이 통과시켜 extract 로 흐르고, 번들 PDF 만 자식 분할된다 (worker-side gating).
await enqueue_stage(session, doc.id, "presegment")
# ★ G2 presegment 인제스트 비활성 (2026-06-18): Option A(자식이 부모 file_path 공유)
# uq_documents_file_path UNIQUE 제약과 충돌 — 자식파일 전략 재설계 후 재활성. 현재=직접 extract.
await enqueue_stage(session, doc.id, "extract")
await session.commit()
except Exception:
# DB 예외 시 session 은 get_session 컨텍스트 종료로 자동 rollback.
+6 -7
View File
@@ -118,18 +118,18 @@ def _route_media(path: Path, expected_category: str | None) -> tuple[str | None,
if expected_category == "library":
# 외부 작성 학습 자료 (KGS Code, 시행규칙 등). 문서 확장자만 수락.
# frontmatter 해석은 classify_worker (옵션 C) 가 담당. file_watcher 는 라우팅만.
# G2 (PR-G2-2): 문서 첫 stage = presegment (extract 前). 非PDF/단일은 통과, 번들 PDF 만 분할.
# ★ G2 presegment 인제스트 비활성(2026-06-18, uq_documents_file_path 충돌) → 직접 extract.
if ext in LIBRARY_DOC_EXTS:
return ("library", False, "presegment")
return ("library", False, "extract")
if ext in AUDIO_EXTS or ext in VIDEO_DIRECT_EXTS or ext in VIDEO_QUARANTINE_EXTS:
return (None, False, None) # audio/video 잘못 들어오면 skip
return (None, False, None) # 기타 알 수 없는 확장자 skip
# Inbox: 문서 파이프 (기존). audio/video 확장자가 실수로 여기 들어오면 skip.
# G2 (PR-G2-2): 문서 첫 stage = presegment (extract 前). 非PDF/단일은 통과, 번들 PDF 만 분할.
# ★ G2 presegment 인제스트 비활성(2026-06-18, uq_documents_file_path 충돌) → 직접 extract.
if ext in AUDIO_EXTS or ext in VIDEO_DIRECT_EXTS or ext in VIDEO_QUARANTINE_EXTS:
return (None, False, None)
return (None, False, "presegment")
return (None, False, "extract")
# ─── Web/Blog ingest (devonagent 트랙) 헬퍼 ──────────────────────────────────
@@ -228,9 +228,8 @@ async def _ingest_web_file(session, file_path: Path, rel_path: str) -> tuple[int
)
session.add(doc)
await session.flush()
# G2 (PR-G2-2): 모든 문서가 presegment 로 진입(단일 entry-point). HTML(非PDF)은 presegment 가
# 변경 없이 통과시켜 extract 로 흐른다 (worker-side gating).
await enqueue_stage(session, doc.id, "presegment")
# ★ G2 presegment 인제스트 비활성(2026-06-18, uq_documents_file_path 충돌) → 직접 extract.
await enqueue_stage(session, doc.id, "extract")
return (1, 0)
+6
View File
@@ -18,6 +18,12 @@ document_lineage(relation_type='segmented_from'). 부모(presegment_role='parent
멱등: 재실행 같은 부모로 이미 자식이 있으면(document_lineage segmented_from) 재생성하지 않고
수렴( 자식이 extract 활성/완료 상태인지만 보장)한다.
BLOCKER (2026-06-18 실측): Option A(자식이 부모 file_path 공유) `uq_documents_file_path`
UNIQUE 제약과 충돌 자식 INSERT UniqueViolation 으로 실패한다. 따라서 **현재 인제스트는 presegment
enqueue 하지 않음**(documents.py/file_watcher.py 직접 extract). 워커는 재설계 전까지 미사용.
재설계 후보: 자식 file_path=unique 합성값(`{parent}#p{s}-{e}`)+실파일은 부모(lineage source)에서 해석
/ 또는 file_path NULL + 별도 bundle_source_path 컬럼. 결정 인제스트 재활성.
plan: G2 pre-segmentation (PR-G2-2 deterministic ToC segmentation)
"""