# relay-baton v0.4.0 릴리즈 노트 날짜: 2026-05-28 ## 요약 v0.4.0은 "harness를 믿을 수 있게" 만드는 버전이다. v0.2는 multi-project layer를 추가했고 v0.3은 안전하게 만들었다. v0.4는 *fallback path 자체*를 관측 가능하고 검증 가능하게 만든다. v0.4 전까지 핵심 orchestration 코드 — 매 Codex → Claude handoff에서 도는 모듈들 — 에 테스트가 없었고, CI도 없었고, harness가 duration / history signal을 안 남겼다. handoff 중 harness가 조용히 잘못 동작해도 알 방법이 없었다. v0.4가 이 틈을 메운다. 하이라이트: - **GitHub Actions CI** — `main` push와 모든 pull request마다. - **fallback path 전체 테스트 커버리지** — workflow, handoff 생성, 두 quality gate, Claude adapter. - **CLI smoke test** — project registry lifecycle. - **Session 관측성** — `session.json`에 `startedAt` / `endedAt` / `durationMs` / `handoffCount`. - **신규 명령** `relay-baton handoff history`. 릴리즈 시점 테스트 총계: **21 test files / 99 tests**, CI에서 전부 green (core 90, cli 9). ## 배포된 내용 ### CI 워크플로우 `.github/workflows/ci.yml`: - Trigger: `main` push, 모든 pull request. - `ubuntu-latest`, Node 20, corepack-pinned pnpm (`packageManager` 필드), `actions/setup-node@v4` + pnpm 캐시. - Steps: `pnpm install --frozen-lockfile` → `pnpm build` → `pnpm test`. - Concurrency group으로 같은 ref의 이전 run 취소. 이전 릴리즈 노트에서 수동으로 들고 다니던 "Validation" 섹션을 대체한다. ### Critical path 테스트 커버리지 매 fallback launch에 참여하는 모듈을 이제 커버: - `BatonWorkflow` — 진짜 temp git repo 대상 fixture 기반 end-to-end handoff build: artifact 생성, budget snapshot 일관성, 모든 diet profile이 `maxHandoffChars` 안에 들어옴, backup-on-overwrite, 큰 diff는 디스크에 두고 inline 안 함, `ultra` truncation이 snapshot에 반영, log fallback phrase가 Known Errors로 노출. - `HandoffGenerator` — 섹션 존재/순서, reference-only 출력, 빈 입력 sentinel, 조건부 라인 (truncated 경고, used chars). - `HandoffQualityGate` — pass + 모든 실패 사유 (파일 없음/빈 파일, 각 필수 섹션 누락). - `TokenDietQualityGate` — profile별 pass / warn / fail (budget, summary 누락, truncate marker, inline guard, caveman/ultra diff bound). - `ClaudeCodeAdapter` — 기본 args, prompt/task fallback, config override, ENOENT 처리, `createAgentEnv` 통한 auth-safety 계약. ### CLI smoke test `packages/cli/src/__tests__/project.smoke.test.ts`가 두 temp git repo 대상으로 `project add / list / switch / current / doctor / remove` 전체 lifecycle을 돌린다. `RELAY_BATON_PROJECTS_FILE`을 temp registry로 가리킴. command function을 직접 import하고 stdout을 intercept — built-binary 의존 없이 같은 vitest pass에서 실행. ### Session 관측성 `SessionMeta`에 optional, 하위 호환 필드 4개 추가: ```ts interface SessionMeta { // ...기존 필드 startedAt?: string; // run/handoff 시작 시점 endedAt?: string; // completed/failed 도달 시점 durationMs?: number; // endedAt - startedAt handoffCount?: number; // 이 세션에서 쓴 총 handoff 수 } ``` `run`과 `handoff`는 진입 시 `startedAt`을 찍고 (stale end 필드 클리어), terminal 전이마다 `endedAt` + `durationMs`를 찍고, 성공적 handoff write마다 `handoffCount`를 증가시킨다. mid-flight 검증 abort (git repo 아님, unknown diet, gate-blocked)는 의도적으로 end 필드를 안 찍음 — 사전 실행 실패이지 완료된 세션이 아니므로. ### `relay-baton handoff history` ```bash relay-baton handoff history [--project ] [--path ] ``` 현재 `.ai-session/handoff.md`와 timestamp가 붙은 `handoff..md` backup들을 최신순으로 나열. 컬럼: timestamp, size, filename, 첫 비어있지 않은 줄을 label로. active 문서는 `*`로 표시. metadata만 — 파일 본문은 절대 dump 안 함. ## 호환성 - `SessionMeta` 추가는 optional 필드. 기존 `.ai-session/session.json`은 그대로 동작하고 다음 `run` / `handoff`에서 채워짐. - `handoff history`는 신규 subcommand. 이름 변경 없음. `handoff --to claude`는 이전과 동일하게 동작하되, `--to` 누락 시 이제 exit code 2 + 명확한 메시지 (이전엔 `requiredOption`이었으나 `handoff history`를 subcommand로 두기 위해 변경). - CI는 런타임 동작에 영향 없음. ## 테스트 중 발견한 주목할 fix `relay-baton handoff history`가 처음엔 모든 진짜 backup 파일을 무시했다: backup 파일명 정규식이 `[\d-]+`였는데 `SessionManager.backupHandoffIfExists`는 `handoff.2026-05-27T05-58-13-213Z.md` 같은 이름을 만든다 (`toISOString().replace(/[:.]/g, "-")` 뒤 trailing `Z`). `[\dZ-]+`로 수정. 새 history 테스트가 잡아냄. ## 다음 개선 추천 (v0.5) [v0.5.0.md](./v0.5.0.md) 참조. headline 기능 2개 계획: - **Plan-execute mode** — 명시적 planner → executor 순서 (Claude가 plan, Codex가 `plan.md`에서 실행). - **Context compression mode** — 진행 중 state / log를 proactive하게 압축해서 agent가 fallback 없이 더 오래 가게. 추가로 이월: OpenCode / Gemini / Aider adapter scaffold, macOS / Windows CI matrix, project-level fallback pattern override.