ISOLATED IMPLEMENTATION PILOT · REPORT OPERATIONS

기존 rN↔rxN은 그대로 두고
비동기 Job 구조만 격리 시험했다

별도 SQLite 원장·임시 포트·새 Codex thread에서 정상 실행과 강제 장애를 시험했다.

기준일 2026-08-16 KST제어면 3회실제 Codex 3회기존 BAT·thread 무변경

BLUF — 방향은 성립하지만 아직 운영 투입은 이르다

비동기 submit
135~196ms
job ID를 돌려준 뒤 작업이 계속돼 Claude turn을 붙잡지 않았다.
장애 복구
3/3 + 3/3
모의 worker와 실제 Codex app-server 강제중단 시험이 수정 후 모두 통과했다.
판정
조건부 Go
v1 실작업 파일럿 가치는 있다. 기존 rN↔rxN은 영구 유지한다.
한계: 실제 장시간 조사→HTML→Hub 등록 전체는 아직 시험하지 않았다. 제어면과 Codex 재연결의 타당성 검증이지 운영 완성 인증이 아니다.

범위와 격리

검증 사실 모든 상태는 research-logs/report-job-orchestrator-pilot-20260816/ 아래에만 생성했다. 기존 codex-relay/, cc_reports1~8.bat, cx_reports1~8.bat의 diff는 0건이었다. 기존 app-server 상태와 rN/rxN thread는 재개·종료하지 않았다.

제어면은 job/attempt 분리, checkpoint, heartbeat, cooperative cancel, append-only event, idempotency key를 구현했다. 실제 Codex는 임시 app-server에서 새 thread를 만들고 정상 turn→서버 재기동→동일 thread resume→turn 도중 서버 종료→thread/read→복구 turn을 수행했다.

정의된 5개 제어면 시나리오와 1개 Codex 장애 시나리오를 각 3회 반복한 표본 시험이다. 재부팅·8개 이상 부하·Hub 동시등록·승인대기는 제외했다.

Exhibit 1. 수정 후 반복 결과

시험방법결과의미
비동기 submitdetached 6-step job 제출3/3, 135·196·135msforeground 대기 제거 가능
병렬 출력두 job 동시·고유 파일3/3고유 보고서 파일은 독립 실행 가능
취소실행 중 cancel3/3heartbeat에서 안전 중단 가능
worker 중단 복구checkpoint 3 후 PID tree 종료→attempt 23/3, effect 각 1회멱등성 키로 중복 부작용 방지
event 감사시작·checkpoint·lost·완료 확인3/3장애 원인 복원 가능
실제 Codex 장애turn 도중 app-server 종료·재기동3/3, 모두 interrupted같은 thread 재개 가능; 중단 turn은 자동 완주되지 않음

환경: Windows, Node 24.16.0, Codex CLI 0.147.0. submit 시간은 로컬 벽시계이며 처리량 지표가 아니다.

Exhibit 2. 시험 중 발견해 고친 문제

로그 부재: 최초 resume worker 실패 때 stdout/stderr를 버려 원인을 볼 수 없었다. 작업별 프로세스 로그를 추가했다.
SQLite 경합: 반복시험에서 모든 연결이 WAL 모드를 다시 설정해 database is locked가 발생했다. 최초 생성 때만 WAL을 설정하도록 수정했다.
resume 원자성: recovery_pending→queuedresume_requested를 transaction으로 먼저 확정한 뒤 worker를 띄우도록 순서를 바꿨다.
Windows 실행: 셸 따옴표·리다이렉션이 최초 app-server 기동을 실패시켰다. Codex JS 진입점을 검증해 Node로 직접 실행했고 shell:true를 제거했다.
상태 reconciliation: 실제 중단 turn이 3회 모두 interrupted로 조회됐다. supervisor는 PID뿐 아니라 SQLite와 Codex thread 상태를 함께 맞춰야 한다.

Exhibit 3. 추가 확인된 장단점

항목판정기존 구조와의 관계
Claude turn 점유submit 즉시 반환 실증새 구조의 명확한 순증 장점
자동 장애 인식worker_lost·interrupted 판별현재 수동 복구를 보완
중복 방지모의 effect만 검증HTML·Hub·외부 API별 키가 더 필요
직접 관찰TUI attach 미구현현재 rx 창이 우세
운영 복잡도DB·worker·supervisor·로그 추가실제 순증 비용
rate limit·공유 파일미검증현재도 존재하며 자동 해결되지 않음
문맥·resume동일 thread 3/3현재 rx도 제공하므로 독점 장점 아님

다음 권고 — topology·lease를 먼저 고친 뒤 재시험

  1. app-server startup mutex: cold-start 단일 owner와 stale lease 회수 규칙을 구현해 공유 PID를 정확히 1개로 만든다.
  2. job CAS·heartbeat: run/resume 중복 호출에서 attempt 하나만 생성하고, 죽은 worker를 running에 방치하지 않는다.
  3. writer lease: followup과 TUI attach가 같은 thread writer를 겹쳐 잡지 못하게 queue/reject한다.
  4. 입력 검증: job ID·brief 경로를 격리 루트로 제한하고 Hub title을 HTML escape하며 turn timeout을 둔다.
  5. Claude 최소안 별도 시험: 현재 relay를 background Bash로 보내 동일 rN을 즉시 재사용하고, 완료 회수·동일 rxN queue를 검증한다.

재시험 합격선: cold-start 3-job에서 app-server 1개, 고아 0, active-writer 충돌 0, worker kill 자동 감지, terminal event 유실 0. 그 전에는 기존 rN↔rxN을 기본 경로로 유지한다.

근거와 미확인

  1. 1차 시험: control-plane-test-result-fixed-run1.json~run3.json, appserver-smoke-result-run1.json~run3.json.
  2. 실제 v1: v1/v1-test-summary.json, v1/three-job-test-summary.json, registrar-fault-result.json, SQLite와 versioned HTML.
  3. 선행 구조 비교 보고서.
  4. OpenAI Codex App Server 공식 문서.
  5. Claude Code background command 공식 문서Hooks·asyncRewake 공식 문서.

미확인 재부팅 복구, 8개 이상 동시 job, 실제 웹 조사형 보고서, startup mutex·worker heartbeat·TUI attach, asyncRewake callback, 실제 Hub와 배포 멱등성.

검증 사실은 JSON·SQLite event·process command line·Codex thread 상태와 생성 HTML에 근거했다. 외부 웹 조사는 Claude 기능 확인을 위한 공식 문서에만 사용했고, 실제 Hub 등록·배포는 하지 않았다.

Exhibit 4. 실제 보고서 v1 수직 실험 — 통과

검증 항목관측값판정
첫 실제 HTML55.2초, 검증 9/9, version 1 보존통과
followup 강제장애app-server 종료 후 0.899초 내 recovery_pending통과
같은 thread 복구직전 turn=interrupted, attempt 3에서 v2 완료 66.346초통과
내용 요구운영 중단 조건·3-job·rN↔rxN 영구 유지 포함통과
격리 registrar2회 호출 후 카드 1개, v2만 연결, v1 파일 보존통과
모바일390px viewport에서 문서 폭 390px, 표만 내부 스크롤통과
추가 발견: 비동기화는 Claude가 기다리지 않게 할 뿐 생성시간 자체를 줄이지 않는다. 실제 보고서는 약 1분이 걸렸으므로 status/watch가 필수다. 현재 CLI가 worker를 직접 spawn하는 방식은 완전한 서비스 경계가 아니며, 운영판에서는 장기 실행 dispatcher가 job 접수와 실행을 분리해야 한다.

근거: v1/v1-test-summary.json, SQLite event 15건, version 1·2 HTML, 격리 Hub. 외부 검색·실제 Hub 등록·배포 없음.

Exhibit 5. 실제 3-job 동시 파일럿 — 기능 통과, topology 실패

항목결과판정
보고서 3종짧은 근거형·큰 표형·상충 근거형, 고유 thread 3·고유 출력 3통과
품질·모바일엄격 문구 누락 1건을 같은 thread followup으로 교정; 390px 3/3통과
DB·격리 Hubintegrity_check=ok, 카드 4·href 4·유실 0통과
registrar faultpublish 전 강제종료 중 기존 Hub hash 유지, 재실행 성공통과
공유 server topologycold-start에서 PID 2840·47312·40032 세 개 생성실패
후속 writer고아 server가 lease를 잡아 already has an active writer실패
전체 판정: no-go. 산출물 기능은 통과했지만 선언한 shared app-server 구조가 깨졌고 실제 followup을 막았다. 격리 PID 소유권과 기존 relay PID 30680의 비중복을 확인한 뒤 테스트 PID만 종료했다. 기존 BAT·codex-relay diff는 0건이었다.

근거: v1/three-job-test-summary.json, registrar-fault-result.json, 세 report HTML과 SQLite attempts/events.

Exhibit 6. 현재 방식에서도 Claude를 먼저 풀 수 있다

즉시 가능한 최소안
Claude가 relay.mjs Bash 호출을 background로 실행하게 한다. Claude Code는 즉시 task ID를 반환하고 같은 rN이 새 prompt를 받을 수 있다.
제약
같은 rxN thread에는 기존 Codex turn 완료 전 새 일반 relay를 겹치면 안 된다. 새 요청은 queue하거나 다른 rx/job으로 보내야 한다.
완료 알림
기본 background 출력은 task ID·파일로 회수한다. idle Claude를 자동으로 깨우려면 asyncRewake hook을 별도 격리 시험해야 한다.

사용자 지시 예: “Codex relay는 Bash background로 넘기고 task ID만 즉시 알려줘. 끝날 때까지 기다리지 마. 같은 rxN이 바쁘면 새 일반 요청은 queue해.” 실행 중인 Bash는 Ctrl+B로 background 전환할 수도 있다. 공식 문서상 background command는 비동기로 실행되고 task ID를 즉시 반환하며 Claude는 새 prompt에 응답할 수 있다. Claude Code Interactive mode

미검증 asyncRewake는 exit code 2로 idle Claude를 깨우고 출력을 system reminder로 전달할 수 있으나, 중복 hook·사용자 turn과의 순서·Claude 종료·보안은 아직 시험하지 않았다. Claude Code Hooks reference

Remote Control만으로는 해결되지 않는다. 입력 UI를 동기화할 뿐 foreground relay의 await turn/completed를 없애지 않는다. 안정 운영은 validated job ID·status/result 파일 또는 SQLite 원장을 함께 써야 한다.