Skip to content

적재 완료 판정에 계약이 없다 — coverage·정리 잔여·프로세스 경계 #161

Description

@epruseal

opencrab.pack.load 의 적재 함수들은 (ok, skip, err) 계열 튜플만 돌려주고, 호출자는 그것으로 "이번 적재가 온전했는가"를 판정할 수 없다.

왜 판정이 안 되는가

err 는 필요조건도 충분조건도 아니다.

  • 필요조건이 아니다: docs.upsert_source 예외가 except Exception: pass 에 삼켜지면 err=0 이 된다. 저장이 실패했는데 온전한 적재로 보인다. (load.py 의 삼킴 자리는 아래 재현 명령으로 전수 확인)
  • 충분조건이 아니다: id_map[node_id] 가 try 밖(load.py:417)이라 문법위반으로 저장되지 않은 노드도 endpoint 로 등록된다. 그 노드를 참조하는 엣지는 endpoint 검사(:564)를 통과하고 add_edge 에서 저장 실패해 err 를 올린다. 문법위반은 결정적이라 다음 실행에도 같은 결과다.

함께 없는 것

  • 정리 잔여(pending cleanup): 타입 변경에서 구 graph 노드는 지워지는데 구 doc 행 삭제가 실패하면 그 사실이 어디에도 안 남는다. 다음 실행은 same 으로 끝나 재시도조차 안 한다.
  • 프로세스 경계: 운영 파이프라인은 로더를 subprocess 로 돌리고 종료 코드만 본다. 결과 객체를 아무리 정교하게 만들어도 경계를 못 넘는다. (호출자 쪽은 opencrab-dump 리포에 별도 등록)
  • readback: 삭제가 실제로 반영됐는지 확인하지 않는다.

설계 요건

  1. 어떤 identity 도 stored_ok | deterministic_skip | retryable_fail | unknown 중 정확히 하나에 속하고, 합이 입력과 다르면 그 자체가 unknown 이어야 한다.
  2. 완료를 ingest_complete / cleanup_allowed / cleanup_complete 로 가른다.
  3. unknown 이 있으면 그 축의 정리를 허용하지 않는다.
  4. 정리 잔여를 durable 하게 남기고 다음 실행이 same 이어도 먼저 처리한다. write-first · fingerprint 조건부 삭제 · idempotent retry 를 만족해야 한다.
  5. 기계 판독 가능한 완료 리포트를 내서 subprocess 소비자가 종료 코드 외에 상태를 읽게 한다.

범위

이관(#93)이 만든 결함이 아니라 이관 전부터 있던 구조다. #93 PR 은 이관 충실성에 집중하므로 여기서 분리한다.

재현

PYTHONPATH=/Users/asdf/localcrab-migration python3 - <<'PY'
import ast, pathlib
src = pathlib.Path("opencrab/pack/load.py").read_text()
for n in ast.walk(ast.parse(src)):
    if isinstance(n, ast.ExceptHandler) and len(n.body)==1 and isinstance(n.body[0], ast.Pass):
        print("삼킴:", n.lineno)
PY

관련

#93 (이관), #160 (타입 변경 공존 창), #158 (영수증 미검사 호출자)

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions