콘텐츠로 이동

동작 원리

이 문서는 판정 기준과 쓰기 순서를 설명합니다. 명령 사용법은 명령에 있습니다.

변경 판정

블록을 같은 파이프라인으로 정규화한 내용으로 비교합니다. 해시는 색인일 뿐, 판정 근거가 아닙니다.

flowchart TB
  M[마크다운] --> IR1[NML IR]
  N[노션 블록] --> IR2[NML IR]
  IR1 --> C[정규 내용]
  IR2 --> C
  C --> E{같은가}
  E -->|같음| Z[변화 없음]
  E -->|다름| A[정렬·판정]
  1. 정규화: 공백을 합치고, 그림: 같은 자리표시자 접두를 떼고, 같은 속성의 인라인 조각을 병합합니다.
  2. 정규 내용: 글자뿐 아니라 굵게·기울임·링크·수식·체크 여부·표 칸·그림 캡션까지 비교합니다.
  3. 정렬: 정확히 같은 내용 → 블록 id → 유사도 순으로 짝을 찾습니다.
  4. 판정: 같음, 수정, 표현 차이, 종류 변경, 넘기기로 나눕니다.

표현 차이는 «종류만 다르고 내용이 같은» 경우입니다. 예를 들어 로컬에는 그림: … 문단이 있고 노션에는 같은 캡션의 그림 블록이 있는 자리입니다. 쓰지 않고 넘깁니다.

세 가지 상태

상태 조건 처리
local_ahead 로컬만 바뀜, 또는 마지막 편집자가 우리 통합 반영 가능
remote_ahead 사람이 마지막에 고침 막음 · pull/keep
conflict 양쪽이 같은 블록을 고침 막음 · pull/keep

base(마지막 동기화 기록)가 있으면 세 값을 비교합니다: base, 로컬, 원격. 없으면 노션이 주는 last_edited_by로 판정합니다. last_edited_by는 마지막 편집자 한 명만 남고 분 단위로 반올림되므로 보조 신호입니다.

쓰기 순서

sequenceDiagram
  participant U as nl push --apply
  participant L as 잠금
  participant S as 스냅숏
  participant N as 노션 API
  U->>L: records/.lock 획득
  U->>S: 페이지 전체 저장
  U->>N: 블록별 PATCH / children / DELETE
  U->>N: 재조회
  U->>U: 검증·저널 마감·base 갱신
단계 실패 시
잠금 다른 실행이 쓰는 중이면 즉시 종료
스냅숏 저장 실패하면 쓰지 않음
블록 적용 댓글 블록은 건너뛰고 목록에 남김
재조회 계획과 다르면 저널에 verify_failed 기록, 스냅숏 경로 출력

안전 게이트

다음 중 하나라도 있으면 push는 아무것도 쓰지 않고 종료 코드 3을 냅니다.

게이트 이유
블록 종류 불일치·종류 변경 자동 변환은 블록을 지우고 다시 만들어야 함
표 열 수 변경 표 재생성 필요, 댓글 앵커 위험
소스 타입 오류 깨진 소스를 반영하면 노션도 깨짐
로컬 재정렬 노션 API에 블록 이동이 없음

댓글이 달린 블록과 표 행은 별도로 건너뜁니다. 확인에 실패하면 «댓글 있음»으로 간주합니다.

저장 위치

store/
  notes/…                      NML 원본
  records/
    snapshots/                 쓰기 전 페이지 사본
    diffs/                     비교 결과
    stage/                     반영할 변경 선택
    base/                      마지막 동기화 상태(선택)
    apply-journal/             쓰기 저널(planned→committed)

노션 API 한도

항목 값
블록 생성 요청당 100개, 중첩 2단계
블록 수정·삭제 1개씩
페이로드 1,000 블록 요소, 500 KB
속도 분당 180회(일반), 600회(Business/Enterprise)

429 응답은 Retry-After만큼 기다린 뒤 재시도합니다.

알려진 한계

  • 같은 글자 블록이 여러 개면 순서로만 짝을 정합니다. 고유 앵커 정렬은 미구현입니다.
  • 블록 이동은 감지만 하고 실행하지 않습니다.
  • 그림 업로드가 없어 그림 블록은 «표현 차이»로만 처리됩니다.
  • 댓글 API는 해석된 스레드를 주지 않으므로 보호 확인에 사각지대가 있습니다.