런타임 데이터와 복구
레코드 식별자, 아티팩트 소유권과 파일 영속성 규칙을 설명합니다.
목적별 정본
현재 코드는 체크아웃 파일과 Git이, 미래 설정은 프로젝트 설정 파일이 소유합니다. 수락된 입력과 관찰된 실행 이력은 런타임 레코드가 소유합니다. 캡처한 설정은 과거 실행을 설명하며 두 번째 편집 가능 설정 레지스트리가 아닙니다. 작성 파일은 설정 소유권에서 정의합니다.
데이터 디렉터리 하나는 고유 식별자와 writer 하나를 가진 로컬 인스턴스입니다. 범용 DB 추상화 대신 JSON과 일반 아티팩트 파일을 사용합니다. 일반 리더는 현재 형식을 읽고, 명시적인 순서의 Umzug 시작 마이그레이션이 지원하는 이전 런타임 기록을 먼저 변환합니다. 알 수 없는 형식은 오류이며 초기화 허가가 아닙니다. 초기화는 명시적 작업이어야 합니다.
레코드
Project 레코드는 불변 식별자·위치와 함께 표시 이름과 선택적 disconnectedAt 시각을
저장합니다. 연결 해제로 증거, 자격 증명, 워크트리나 소스 파일을 연쇄 삭제하지 않습니다.
재연결은 같은 레코드에서 해당 시각을 제거합니다. 프로젝트 관리를 참고하세요.
| 레코드 | 의미 |
|---|---|
| Project | 연결된 저장소·하위 디렉터리 또는 일반 디렉터리 식별 |
| Worktree | 과거 체크아웃 식별과 프로젝트 연결 |
| Work item | 해당 프로젝트·워크트리의 캡처된 작업 의도 |
| Submission | 불변 테스트·helper 소스, digest, 파싱한 의도와 실행기 식별 |
| Integration run | 제출, 수락한 대상·설정·Git, 실행 상태와 결과 |
| Environment | 고정 서비스·의존성 종류, 소스 식별, 소유 리소스와 수명주기 |
| Work start | 읽기 전용 과거 체크아웃 생성 입력, 계획된 출력과 관찰 상태 |
| Review | 캡처된 MCP 정책·승인·캡처된 구성·revision과 실행 연결 |
| Unit run | 명령·런타임 식별, 출력, 최종 상태와 정리 상태 |
| Playwright run | 타깃·시나리오 결과와 브라우저 아티팩트 |
| Merge attempt | 검사한 소스·대상 식별자, 진행과 복구 결과 |
과거 work-starts/ 기록은 기존 형식과 원본 바이트를 보존합니다.
제거된 생성 기능에는 쓰기나 재개 작업이 없습니다. 이 기록은 경로를 예약하거나
프로젝트 연결 해제를 막지 않습니다. 기존 체크아웃 연결은 현재 Git과
파일시스템 관찰을 사용합니다. 데이터 마이그레이션이나 초기화는 필요하지 않습니다.
Work item은 제출 여러 개를, 제출은 실행 여러 개를 가질 수 있습니다. 새 관리 실행마다 자체 환경을 사용합니다. 수동 환경에는 run ID가 없으며 실행 증거가 아닙니다. ID와 복사된 대상 연결은 일치해야 하지만 DB foreign key나 파일 간 트랜잭션은 없습니다.
물리적 소유권
<data-dir>/
├── .migrations/completed.json # 순서가 있는 Umzug 마이그레이션 이름
├── .migrations/backups/<migration>/ # 변경한 레코드의 원본 바이트
├── instance.json, settings.json
├── projects/, worktrees/, work-items/, submissions/
├── work-starts/, reviews/, execution-reviews/, unit-runs/, merges/
├── runs/<id>/
│ ├── state.json
│ ├── source/, report.json, vitest.config.mjs
│ └── connections.json, stdout.log, stderr.log
├── environments/
│ ├── <id>.json
│ └── <id>/ # 준비 로그와 임시 입력
├── playwright-runs/ # Playwright 레코드와 아티팩트
├── .writer.guard # 영구 OS 잠금 inode
└── .writer.lock # 현재 프로세스 소유권정확한 현재 레이아웃과 버전은 storage adapter가 정의합니다. 트리는 내보내기 스키마가 아닌 소유권 설명입니다. 리소스 ID·endpoint·서비스 관찰값은 환경에 포함되는 증거이며 독립 관리 엔티티가 아닙니다. Docker와 앱 데이터는 파일 밖에 있으며 Redpact가 백업하지 않습니다.
버전별 시작 마이그레이션
앱은 기존 인스턴스 writer lock을 획득하고 .migrations/completed.json을 확인한 뒤,
인스턴스 설정 로드·리소스 복구·HTTP/MCP 요청 수락보다 먼저 미적용 Umzug 마이그레이션을
실행합니다. 순서가 있는 마이그레이션 이름이 제품 SemVer 및 레코드 봉투의 version: 1과
별도로 인스턴스 저장 형식을 관리합니다. 완료 이력은 앱 마이그레이션 목록의 앞부분과
일치해야 합니다. 알 수 없는 이름, 중복, 순서 변경, 잘못된 JSON은 이력을 지우지 않고
시작을 차단합니다. 이력이 없으면 빈 설치를 포함해 지원하는 마이그레이션 이전 형식에서 시작합니다.
001-fixed-environment-settings는 구형 환경의 specification.dependencies.modes를
각 환경에 캡처된 selection.select에 따라 고정 정의로 변환합니다. 루트 services가
없으면 캡처된 selection.services를 사용합니다. 추천값으로 선택을 추측하지 않습니다.
선택 누락, 지원하지 않는 형식, 잘못된 레코드는 경로를 표시하며 시작을 차단합니다.
현재 형식의 레코드는 바이트 단위로 그대로 둡니다. ID, 시각, digest, 해석된 실행 입력,
캡처 소스를 보존합니다. 사용하지 않은 모드와 평가를 포함한 원래 specification은
원본 바이트 백업에 남고, 활성 레코드에는 선택된 고정 정의가 들어갑니다.
Umzug는 버전별 미적용 변환을 메모리에서 순서대로 적용합니다. 각 변환의 입력 계약은 현재 작성 스키마와 독립적으로 고정합니다. 모든 변환 후 최종 현재 형식을 검증하고, 파일 교체 전에 모든 환경 입력을 검사합니다. 변경할 각 파일은 기존 원본을 덮어쓰지 않는 내구성 있는 백업을 먼저 만들고 원자적으로 교체합니다. 완료 이력도 모든 미적용 변환과 파일 교체가 성공한 후에만 원자적으로 교체합니다. 중단 후 재시작하면 첫 미적용 마이그레이션 아래의 백업을 재사용해 미완료 작업을 끝내며, 백업과 예상 변환 결과 모두와 다른 레코드는 거부합니다. 여러 파일 전체가 하나의 트랜잭션은 아니므로 중단 시 일부만 변환될 수 있지만 원본은 남고 완료는 기록되지 않습니다. 이는 프로세스 중단 복구이며 일반적인 파일시스템 재해 복구 보장은 아닙니다.
백업 대상은 변경한 런타임 레코드뿐이며 전체 인스턴스, Docker 볼륨, 프로젝트 파일이
아닙니다. 백업은 자동 삭제하지 않습니다. 롤백이 필요하면 업데이트 전에 전체 인스턴스를
백업해야 합니다. 자동 다운그레이드와 down 명령은 없으며, 앱을 종료한 상태에서
일치하는 앱과 전체 데이터 백업을 함께 복원합니다. 이 기능 이전 앱은 이력을 이해하지
못하므로 업그레이드한 데이터를 열면 안 됩니다. 다운그레이드를 강제하려고 이력이나
writer lock을 삭제하지 마세요.
작성하는 프로젝트 .redpact/settings.json은 여전히 구성의 단일
고정 계약을 사용합니다. 시작 마이그레이션이 저장소를 수정하거나 인프라를 대신 선택하지
않습니다. 첫 마이그레이션은 인스턴스 settings.json도 변경하지 않습니다. 이후 저장 설정이
바뀌면 이전 입력 검증, 원본 보존, 중단 복구 테스트를 갖춘 순차 마이그레이션을 추가해야
합니다. 업그레이드 경로 없이 과거 스냅샷을 새로운 작성 스키마에 묶으면 안 됩니다.
저장과 복구
비공개 임시 파일에 쓴 뒤 완전한 레코드를 원자적으로 rename합니다. 불변 레코드는 덮어쓰지 않습니다. 형식·부모 연결·식별 불변식을 검사하고 손상은 초기화나 생략 대신 보고합니다. Writer lock은 프로세스 소유권을 기록합니다. 살아 있거나 알 수 없는 프로세스의 lock을 빼앗지 않습니다.
CLI와 App의 공통 런타임은 시작부터 실행과 종료까지 영구 파일
.writer.guard에 OS 권고 잠금을 유지합니다. 이 잠금은 소유자 복구를 직렬화하며,
강제 종료를 포함해 프로세스가 죽으면 커널이 해제합니다. 파일이 비어 보여도
삭제하거나 교체하지 마세요. guard 파일이 남아 있다는 사실만으로 실행 중이라는 뜻은 아닙니다.
이 guard를 획득한 시작 프로세스는 .writer.lock의 유효한 PID 메타데이터에 대해
OS가 해당 프로세스의 부재(ESRCH)를 확인한 경우에만 자동 복구합니다. 이전 소유자
파일은 .writer.lock.stale-<id>로 보존하고 레코드, 마이그레이션, 설정과 증거는
변경하지 않습니다. 소유자 메타데이터를 원자적으로 게시하므로 초기화가 중단돼도
불완전한 새 소유자 파일이 노출되지 않습니다. 동시 시작에서는 하나의 writer만
허용하며, 나머지는 잠김 오류를 받고 소유자가 종료된 뒤 다시 시도할 수 있습니다.
살아 있거나 재사용된 PID, 권한 거부로 확인할 수 없는 프로세스, 손상되거나 알 수
없는 소유자 정보는 파일을 삭제하지 않고 시작을 차단합니다. 이 경우 소유자를
확인하고 종료한 뒤 수동 복구해야 합니다. 자동 복구는 로컬 파일시스템과 동일한
호스트 PID 네임스페이스를 전제로 합니다. 서로 다른 컴퓨터나 별도 PID
네임스페이스의 컨테이너 사이에 인스턴스 디렉터리를 공유하지 마세요.
이 운영용 잠금 파일은 레코드 형식을 바꾸지 않으며 데이터 초기화나 마이그레이션이 필요하지 않습니다.
종료는 새 연결 수락을 중단하고 모든 정리를 순서대로 시도하며 실패를 모아 보고합니다.
중복 요청은 같은 정리 작업의 완료를 기다립니다. 정리가 성공한 뒤에만 writer 잠금을
해제합니다. 정리에 실패하면 최종 동기식 종료 정리까지 소유권을 유지하고 0이 아닌
상태로 프로세스를 끝내므로, 미완료 writer가 교체 프로세스와 겹치지 않습니다.
강제 종료는 시작 시 복구로 처리합니다. SIGKILL이나 전원 손실은 시그널 핸들러로 처리할 수 없습니다.
예약, 실행 저장과 리소스 생성은 파일·프로세스 경계를 넘습니다. 부분 완료를 대조할 수 있도록 작업별 상태를 보존합니다. 복구는 실행 증거를 꾸미거나 수락한 입력의 대상을 바꾸거나 불확실한 시작을 재실행하면 안 됩니다. 대기 승인은 재시작 후에도 남으며 불확실한 starting 요청은 interrupted가 되어 확인을 요구합니다. 정리 중에도 최종 판정은 유지합니다.
환경 종료는 소유 런타임 리소스와 캡처 소스·런타임 파일을 제거하고 메타데이터와 로그를 보존합니다. Unit은 실행별 이미지를 제거하고 Playwright는 공유 러너 이미지를 유지한 채 캡처 컨테이너를 제거합니다. 워크트리가 사라져도 과거 결과는 남습니다. 임시 Compose 빌드 이미지는 환경과 함께 제거하지만 Docker 빌드 캐시와 명시적으로 이름 붙인 프로젝트 이미지는 prune하지 않습니다. 일반 자동 증거 보관·삭제 정책을 의미하지 않으며, 참조된 레코드를 수동 삭제하면 이를 사용하는 데이터가 깨질 수 있습니다.
Unit과 Playwright의 Ask 요청은 추가된 execution-reviews/<id>.json에 version: 1로
저장합니다. 실행 명세·설정 및 입력 digest·정책·revision·UI capability·최종 실행 연결을
보존합니다. 기존 Integration reviews/와 실행 기록의 형식 및 원본 바이트는 바꾸지 않으므로
이 추가 기록 종류에는 이전 기록 변환이 없습니다. 앞으로 이 형식을 바꾸면 위의 순서 있는
마이그레이션 규칙을 따라야 합니다. 알 수 없는 버전이나 손상된 검토는 초기화하지 않고
시작을 막습니다.
대기 중 Unit/Playwright 검토는 재시작 후에도 승인할 수 있습니다. 실행 수락 도중 중단된
starting 검토는 interrupted로 남고 재실행하지 않습니다. 실행 시작 후 검토의 최종 연결
저장에 실패해도 불확실한 시작을 보존합니다. 재요청 전에 연결된 실행 이력을 확인하세요.
검토 취소는 근거나 기록을 삭제하지 않으며 승인과 실행 verdict는 별개입니다.
환경변수 값과 증거
환경변수 문자열은 공유 설정과 캡처한 설정·소스 기록에 평문으로 남습니다. 새 실행은 private-secrets 파일을 만들거나 서버 환경변수 fallback을 읽지 않습니다. 마스킹과 평문 범위는 환경변수 값을 참고하세요. 검토 capability는 모델에 노출하면 안 됩니다. 이미지와 변환된 출력에는 민감한 정보가 남을 수 있으며 실행 증거는 로컬 데이터이지 공개 내보내기가 아닙니다.
002-flat-environment-values 마이그레이션은 과거 환경 기록을 문자열 값으로 바꿉니다.
리터럴 래퍼를 풀고 기존 내부 DNS 규칙으로 서비스 host/port/URL 바인딩을 변환합니다.
비밀값 참조는 저장된 private-secrets/environment-<id>.json 스냅샷으로만 해석하며
현재 프로젝트나 서버 값으로 대체하지 않습니다. 캡처 값이 없거나 잘못되면 기록을
덮어쓰지 않고 시작을 중단합니다. 재시도 전에 인스턴스 백업에서 해당 실행의 스냅샷을
복구하세요. 원본 기록은 첫 대기 마이그레이션 아래에 백업합니다. 캡처 소스, digest,
과거 비공개 파일은 보존하며 일반 실행은 이 비공개 파일을 읽지 않습니다. 작성한
설정은 설정 계약에 따라 수동으로 바꿔야 합니다.
구현: storage adapters, 레코드 계약, 검토 저장, 캡처 저장.
003-execution-selection 마이그레이션은 과거 제출, Unit/Playwright 실행과 실행 검토에
선택을 알 수 없음(null)을 명시합니다. 기존 순서형 마이그레이션 백업에 원본 바이트를
보존하고 교체 전에 기록을 검증하며 중단된 변경을 재시도합니다. 과거 파일 목록을
추정하거나 결과를 변경하지 않습니다. 새 기록은 실행의 선택 계약을 담습니다.
인스턴스 데이터 디렉터리의 runtime-lifecycle.jsonl에 부모 연결과 독립적으로
런타임 진단을 동기식 추가 기록합니다. PID/시각, 시작 요청·완료·실패, 종료 원인
(manual, update, parent_disconnect, SIGINT, SIGTERM, server_error),
정리 오류, writer 해제 및 오래된 소유자 회수를 기록합니다. 설치된 CLI supervisor는
자식 PID, 종료 코드와 시그널도 기록하여 supervisor가 살아 있는 동안 자식의 강제
종료를 관측합니다. CLI가 받은 SIGINT/SIGTERM은 supervisor와 자식 기록 모두에서
종료 원인으로 유지됩니다. 종료 시 이미 수락한 HTTP 핸들러가 끝난 후 writer
소유권을 해제합니다. 두 프로세스 모두 SIGKILL되면 최종 기록을 남길 수 없습니다.
로그는 자동 회전 없이 보존되며 인스턴스를 중지한 상태에서만 보관 처리해야 합니다.
살아 있거나 재사용된 PID는 회수하지 않으며 손상된 메타데이터와 생존 확인 실패의
거부 원인을 구분합니다. 새 진단 기록은 이전 종료의 최초 원인이 확인되었다는 뜻이 아닙니다.
004-manual-environment-scope 마이그레이션은 기존 수동 환경에 manualScope: "main"을
기록합니다. 이전 계약에서는 설정된 메인 체크아웃에서만 생성했기 때문입니다. 테스트 기록과
과거 증거는 변경하지 않습니다. 새 수동 환경은 시작할 때 main 또는 worktree를 캡처하며
이후 브랜치 변경으로 포트 정책을 바꾸지 않습니다. 원본 바이트와 중단 후 재시도는 위의
순차 마이그레이션 규칙을 따릅니다. 수동 환경 소스와 생성된 runtime/ 파일은 명시적
teardown 성공 후 제거하며 서버 종료는 재연결에 필요한 소유권을 보존합니다.
이전 무라벨 빌드 이미지의 컨테이너를 제거하기 전에 정리는 캡처된 암묵적 빌드와 현재
관측한 소유 컨테이너를 근거로 environments/<id>/runtime/legacy-image-ownership.json을
원자적으로 기록합니다. 이 생성된 작업 산출물은 각 태그를 불변 이미지 ID, 환경, 인스턴스
소유자와 Docker 런타임에 연결하며 과거 기록을 변경하지 않습니다. 부분 실패 시 보존하여
컨테이너가 사라진 뒤에도 재시도할 수 있습니다. 증거가 없으면 현재 관측한 소유권이
필요하며 손상되거나 불일치하는 증거와 교체된 이미지는 삭제를 허용하지 않습니다.
teardown 성공 시 이 산출물을 제거합니다.
업데이트 사전 검증과 명시적 이력 초기화
개발용 pnpm local:update는 후보 버전의 HTTP/MCP/UI를 확인한 뒤 인스턴스 데이터를
임시 복사본으로 만들고, 기존 서비스를 종료하기 전에 후보 버전의 마이그레이션과 실행
기록 검증을 복사본에서 수행합니다. 현재 writer guard·소유자 파일은 복사 대상에서
제외합니다. 서버·복구·테스트를 시작하거나 Docker 작업을 실행하지 않습니다. 실패하면
기존 서비스를 계속 실행하고 임시 복사본을 제거합니다. 이는 마이그레이션 호환성 검사이며
원자적 스냅샷이나 준비 완료 보장은 아닙니다. 복사 중 데이터가 바뀔 수 있으므로 실제
시작 시에도 writer lock을 보유한 상태에서 실제 인스턴스를 검증합니다.
실행 선택 변경은 003-execution-selection이 아직 적용되지 않았을 때만 수행합니다.
최신 기록 검증은 보류된 변환 이후, 모든 파일 교체 이전에 수행합니다. 실행 기록 오류에는
기록 종류와 파일 경로를 표시합니다. 중단 후 재시도 시 이미 선택 정보가 있는 기록도
현재 내용이 원본 백업 또는 예상 변환 결과와 일치해야 하며, 다르면 덮어쓰지 않습니다.
검증 실패 전에 백업이 작성되었다고 보장하지 않습니다. 변경되지 않은 원본은 기존 위치에
그대로 남아 있을 수 있습니다.
지원하지 않는 과거 형식은 명시적인 오류로 처리합니다. 수명주기 필드가 없다는 이유로 정리 성공을 추정하지 않으며, 결과를 만들어 넣거나 손상된 증거를 건너뛰거나 이력을 자동으로 초기화하지 않습니다. 사용자가 명시적으로 허용한 이력 초기화는 서비스를 멈춘 상태에서 전체 데이터를 백업한 뒤 실행 기록·산출물과 해당 승인을 함께 분리하는 유지보수 작업입니다. 인스턴스 식별자, 설정, 프로젝트·워크트리 등록은 유지합니다. 환경 리소스를 확인·정리하기 전에는 소유권 기록을 보존하고, 실행 이력이 초기화됐다는 이유만으로 Docker 리소스를 삭제하지 않습니다. 검증을 우회하려고 마이그레이션 완료 이력을 지우지 말고 해당 기록과 함께 보관하세요. 제품에는 자동 이력 삭제나 일반 초기화 명령이 없습니다.