실행 기록
모든 실행은 노트북 하나를 남깁니다
출력을 로그 파일로 돌릴 필요가 없습니다. 커널이 실행마다 소스 파일 옆에 nbformat 4 노트북을, 실행하는 동안 계속 씁니다.
__runs__ 폴더
experiments/
├─ train.py
└─ __runs__/
└─ train.py/
├─ 20261003-142233-a1f0.ipynb
├─ 20261003-150102-77c2.ipynb
└─ index.json
- 실행 하나는 요청 하나입니다. 파일 전체든 셀 몇 개든 같습니다.
run_id는 UTC 기준YYYYMMDD-HHMMSS-<4 hex>라서 이름순이 시간순입니다.index.json은 실행 목록을 최신순으로 ID, 상태, 시작, 끝, 모드와 함께 담습니다. 깨지면 다시 만듭니다..ipynb는 어떤 Jupyter 뷰어로도 열립니다. 노트북의metadata.darkpyonix에는 run id, 커널 ID, 파일 해시, 모드, 파라미터, 상태, 시각, 인터프리터, 호스트가 들어 있습니다.
기록 방식
커널은 실행 중에도 최대 1초 간격으로 기록을 원자적으로(임시 파일 뒤 이름 변경) 다시 씁니다. 커널이 죽어도
파일은 유효한 JSON이고, 죽기 약 1초 전까지의 출력이 들어 있습니다. 상태는 running으로 남고, 그
파일의 다음 커널이 crashed로 바꿉니다.
상태 값은 running, ok, error, interrupted,
crashed입니다. 셀 하나의 스트림 출력이 16 MiB(DARKPYONIX_RUN_OUTPUT_LIMIT)를 넘으면 나머지는 노트북 옆 <run_id>.cell<index>.log에 씁니다. 노트북이 열 수 있는 크기로 남게 하기 위해서입니다. 실시간 이벤트에는 제한이 없습니다.
기록과 셀 맵핑
기록 안의 셀마다 번호, 타입, 제목, 상태, 시각, 그리고 셀 본문의 해시 source_sha256이 있습니다.
편집기는 최신 기록을 id, 소스 해시, 번호 순서로 파일의 셀에 맵핑합니다. 실행 뒤 소스가 바뀐 셀은
"이전 소스의 결과"로 보여 줄 수 있습니다.
__runs__ 변수
커널 안에서는 같은 기록이 변수로 보입니다. 그래서 사람이든 에이전트든 코드에서 파일을 열지 않고 지난 결과를 읽습니다.
run = __runs__.latest # 마지막으로 끝난 실행, 없으면 None
run.run_id, run.status, run.params # '20261003-150102-77c2', 'ok', {'lr': 0.01}
run.cells[0].text # 기록된 첫 셀의 표준 출력
run.cell("Train").result # 그 셀 마지막 식의 repr
__runs__.list(limit=5) # 최신순 요약
__runs__.current.path # 지금 쓰고 있는 .ipynb 경로
실행과 셀은 속성 접근이 되는 dict 하위 클래스입니다. 속성은 먼저 dict 키에서, 없으면
metadata.darkpyonix에서 찾습니다. cell.text는 stdout을, cell.stderr는
stderr를 이어 붙인 문자열이고, run.cell(key)는 ID, 제목, 파일 셀 번호로 셀을 찾습니다.
json.dumps(run)은 노트북을 그대로 돌려주며, 반환값을 바꿔도 기록은 바뀌지 않습니다.
변수 자체는 저장하지 않습니다. 값이 다시 필요하면 기록에 남은 코드를 다시 실행합니다.
기록과 Git
__runs__/는 기본적으로 Git에 포함합니다. 실행 기록도 작업의 일부이기 때문입니다. 원하지 않으면
.gitignore에 넣습니다.