← 목록
기타 2026-06-26 42KB 읽기 42분

크라우니엔진 아키텍처

크라우니엔진 (@crowny/engine) — 최종 아키텍처 + 빌드플랜

적대검토의 높음/중간 이슈를 전부 반영해 초안을 재설계한 확정본이다. 가장 큰 변화 세 가지: (1) 구독은 "서버가 쥔 가치"에만 건다(로컬 claude 페이월 폐기), (2) 지갑·회원·환율은 자체 포크하지 않고 bank/회원/dex 서비스를 호출한다, (3) 정산·지갑쓰기는 엔진서버 단일 라이터로 직렬화하고 정산 발화는 별도 크론으로 분리한다.


0. 적대검토 이슈 → 해소 매핑 (전 항목)

ID등급해소
A1 로컬 claude 페이월 불가높음구독 가치 재정의: 페이월 대상 = 서버측 가치(일일패키지 다운로드·학습DB sync·블록체인 앵커·멀티유저 슬롯·세션 대장·포터블 번들). 로컬 claude 실행은 막지 않음. 문구 정정: "engine-pro = 크라우니 협업 서비스 구독". claude실행.sh는 게이트가 아니라 세션 대장 기록만 수행(미구독시 로컬 실행은 되되 서버 기능 비활성).
A2 정산이 accept 루프에 묶임높음정산을 별도 LaunchAgent 크론 com.crowny.engine-settle(core/정산.한선 배치, 매일 1회)로 분리. 인-루프 타이머 가정 폐기. 요청시 catch-up은 보조.
A3 지갑 TOCTOU 이중지불높음엔진서버 단일 라이터. .sh는 원장에 직접 쓰지 않고 API 경유. 잔고 = 원장 합(SSOT). 추가는 쓰기가 아니라 덧쓰기(). (단 잔고 정본은 bank — B1 참조)
A4 바이너리 tgz를 한선씨 문자열로 서빙높음tgz는 게이트웨이 정적 경로로 서빙(/packages/... → 파일시스템 직빵). 엔진서버는 메타데이터(JSON)만 반환, 바이너리 스트리밍 안 함.
B1 지갑 자체포크+없는 경로 인용높음자체 지갑.한선 폐기. crowny-bank API 호출(잔고/차감/입금). 엔진은 과금 의도만 발생시키고 가치이동은 bank가 집행. 금융/crowny-wallet.한선 인용 삭제.
B2 회원 DB 포크높음자체 accounts.json 폐기. 기존 회원 서비스(crowny-data/services/회원계정.한선) 호출. 엔진은 user→회원ID 매핑만 로컬 보관.
B3 copy가 SSOT 깨뜨림중간copy 폐기 → libs/ 심볼릭 + 가져오기 참조. 인증판정·세션이관·싱크체인·분업규칙 전부 정본 참조.
B4 stub 성격 오판(admin API)중간stub은 /api/admin/requests 관리 API. legacy 이동 보류 → KPS 확인 전까지 admin-server는 그대로 두고, 엔진서버는 9761을 공유하지 말고 신규 포트 할당(아래 0.1).
B5 환율 자체발명중간FX 폐기. 환전 필요시 dex API 호출. 엔진엔 환율 상수 없음.
C1 6561 슬롯 vs 배열 1023 상한중간슬롯/사용자 순회는 맵 또는 범위샤딩. 6561 슬롯 개념 폐기(F3). 정산 순회도 샤딩(>1023 무료 누출 차단).
C2 나눗셈 자연반올림중간일수·월키 epoch 환산 전부 절단헬퍼 명시 적용.
C3 가져오기 side-effect중간모든 wrap 대상은 import 전 top-level 기동문 검증, 있으면 *_lib.한선 함수부 추출본 생성 후 import.
C4 앵커 /tmp 경쟁낮음/tmp/anchor.<pid>.<height> 고유 경로.
C5 실행중 .toau 교체낮음mv 원자 rename(빌드→/tmp/엔진서버.toau.new→mv).
D1 포터블 복원 경로주입높음tar --no-absolute-names, ../절대경로 엔트리 거부, 추출 전 싱크체인 해시 서명검증, 경로복원 화이트리스트.
D2 멀티유저=네임스페이싱중간API per-user 인증 강제 + 파일권한. 문서에 "OS격리 아님" 정직 기술.
D3 부트스트랩 curl\bash중간다운로드 후 체크섬/서명검증 후 실행, 인라인 파이프 금지.
E1 grace 자기모순중간active-but-overdue 상태 도입: 잔고부족=즉시 paused 아님 → overdue 마킹, day30에 paused로 일원화.
E2 과금주기 혼용중간달력월(YYYY-MM) 멱등키 단일 채택. nextBillAt +30d 롤링 폐기. 가입월=즉시 첫달 차감(보너스 2000 입금 직후 차감 → 사실상 첫달 무료 효과는 정책으로 별도 결정, 기본은 즉시차감).
E3 일일빌드 동시실행중간flock 락파일 + 원자 rev 증가.
E4 diff 삭제 표현 불가중간diff 매니페스트에 삭제목록 + 각 diff에 base-rev 핀, 클라가 base rev 검증 후 적용.
E5 학습.dat dedup 무력화+디스크폭증중간학습DB는 번들에서 제외, crownycode-learn.sh sync 전용 경로. daily/ 회전 정책(최신 N개) 강제.
E6 클럭점프 월스킵낮음lastBilledMonth~now 사이 누락 월 전부 순회 과금.
F1 이중 체인중간블록체인앵커 + 싱크체인 → 단일 체인 추상(core/체인.한선)으로 통합. 감사·빌드싱크 같은 체인.
F2 차감마다 원격앵커낮음daily 배치앵커 또는 분쟁/정지만 앵커.
F3 6561/effort 토큰매핑낮음6561 폐기. effort는 실제 CLI 플래그 검증 후 매핑(미검증이면 env 주입만, 가정 명시 안 함).

0.1 포트 결정 (B4 반영 — 변경됨)

초안은 9761 공유를 가정했으나, 9761은 가동 가능한 admin API stub이다. legacy 이동은 KPS 확인(음→이관) 전까지 보류. 따라서 엔진서버는 신규 포트를 crowny-ports.sh free로 할당하고 crowny-ports.sh set crowny-engine-api <포트> 선언한다. 9761/admin-server는 무접촉. (runbook에 "KPS 확인 후 9761 통합 가능" 메모.)


1. 아키텍처 (이중 레이어 + 서버측 가치 페이월)

                 ┌──────────────────────────────────────────┐
   사용자 맥      │  shell/*.sh  (플랫폼락: claude spawn, tmux,  │
   (로컬 claude)  │  env, 터미널)  ── 각 .한선 동반(판정부)      │
                 └───────────────┬──────────────────────────┘
                                 │ curl (model/effort 해석, 세션대장,
                                 │       패키지 update-check)
                 ┌───────────────▼──────────────────────────┐
   엔진서버       │  core/엔진서버.한선 (:신규포트)             │
   (가치 보유)    │  - 세션 대장/제목  - 패키지 메타            │
                 │  - 멀티유저 슬롯   - effort/model 라우팅    │
                 └───┬──────────┬──────────┬─────────┬───────┘
                     │호출       │호출       │호출      │append
              ┌──────▼──┐ ┌─────▼────┐ ┌───▼────┐ ┌──▼──────────┐
              │crowny-  │ │crowny-   │ │crowny- │ │core/체인.한선 │
              │bank     │ │회원서비스 │ │dex     │ │(단일 해시체인)│
              │(잔고/과금)│ │(계정SSOT) │ │(환율)  │ │ +9729 배치앵커│
              └─────────┘ └──────────┘ └────────┘ └─────────────┘
   (별도) com.crowny.engine-settle → core/정산.한선 (매일 크론, 단일 라이터)
   (별도) com.crowny.engine-dailybuild → shell/일일빌드.sh (매일 10시, flock)

핵심 원칙

  • 결정로직 = .한선 SSOT, 플랫폼호출 = .sh(동반 .한선 판정부). 헌법 한선씨 동반 강제 충족.
  • 가치 SSOT는 엔진이 소유하지 않는다: 잔고=bank, 계정=회원서비스, 환율=dex. 엔진은 오케스트레이터다.
  • 정산·지갑변이는 단일 라이터(엔진서버 또는 정산크론 中 락으로 직렬화). .sh는 절대 직접 안 씀.
  • 바이너리는 게이트웨이 정적 서빙, 한선씨는 메타데이터(JSON/텍스트)만.

2. 디렉토리 레이아웃 (확정)

/Users/ef/crowny-engine/            # 기존 디렉토리 재사용, admin-server/server.js 무접촉
├── CLAUDE.md                       # 패키지 규칙 + VM함정 + 서브에이전트 가드레일 주입
├── package.json                    # @crowny/engine, deps: @crowny/crownyc ^10.3
├── README.md
├── 엔진.sh                         # 단일 진입 디스패처(run/user/model/sub/pkg/sync/serve/title)
│
├── bin/
│   ├── crowny-engine               # PATH 런처 → 엔진.sh
│   └── 엔진서버기동.sh             # (nohup crownyc run /tmp/엔진서버.toau >log 2>&1 </dev/null &)
│
├── core/                           # ── 한선씨 결정·서버 정본(SSOT) ──
│   ├── 엔진서버.한선               # HTTP API(:신규포트). lib만 import, 본인이 기동
│   ├── 정산.한선                   # 배치 정산(크론 진입점). 단일 라이터
│   ├── 구독게이트.한선             # 판정·overdue·연체단계 (구독판정 참조+확장분만)
│   ├── 과금클라이언트.한선         # bank API 호출 래퍼(잔고/차감/입금) — 자체지갑 아님
│   ├── 회원클라이언트.한선         # 회원서비스 API 호출 래퍼 — 자체 accounts 아님
│   ├── 환율클라이언트.한선         # dex API 호출(환전 필요시만)
│   ├── 체인.한선                   # 단일 해시체인(감사+빌드싱크 통합) + 9729 배치앵커
│   ├── 분업라우팅.한선             # 작업유형→model, model→CLI ID
│   ├── effort판정.한선             # low~max 검증·쿼리오버라이드·예산
│   ├── 세션제목.한선               # 첫프롬프트→title 도출·슬러그·rename
│   ├── 패키지빌드판정.한선         # diff/해시중복제거/삭제목록/base-rev 핀
│   ├── 매니페스트.한선             # tier-manifest 파싱·번들대상·시크릿마스킹
│   ├── 시간헬퍼.한선               # 절단 나눗셈·월키·일수(C2)
│   └── 인증판정.한선 → libs/심볼릭 # (copy 아님, 정본 참조)
│
├── shell/                          # ── 플랫폼락 .sh + 각 .한선 동반 ──
│   ├── claude실행.sh / .한선        # claude 호출(model/effort env) / 인자조립·세션기록 판정
│   ├── 멀티유저.sh / .한선          # CLI 사용자 전환 / 슬롯배정·격리경로 판정
│   ├── 인터랙티브.sh / .한선        # REPL(턴마다 model/effort/:cmd) / 턴파싱·라우팅
│   ├── 세션제목설정.sh             # title 세팅+rename → 대장+LIVE_STATUS
│   ├── 일일빌드.sh / .한선          # flock 일일 diff 빌드 / 빌드대상·중복제거 판정
│   ├── 정산기동.sh                 # 크론 래퍼 → crownyc run 정산.toau
│   ├── 포터블복원.sh               # 번들 서명검증→안전 tar 추출→경로복원
│   └── 부트스트랩.sh               # 다운로드→체크섬검증→설치(curl|bash 금지)
│
├── data/
│   ├── tier-manifest.psv           # 번들 SSOT(crownyc 소스행 추가, 학습DB 제외)
│   ├── 분업규칙.psv → 심볼릭        # skills/분별 정본 참조
│   ├── plans.json                  # engine-pro = 2000 CRD/월
│   ├── users/<user>/               # session.json, model.cfg (잔고/원장 없음 — bank가 보유)
│   ├── usermap.json                # OS user → 회원ID 매핑(B2)
│   ├── subscriptions.json          # status(active/overdue/paused)/lastBilledMonth/overdueSince
│   ├── chain/{wal.log, chain.json} # 단일 체인 영속(F1)
│   ├── packages/
│   │   ├── base/<rev>.tgz
│   │   └── daily/<YYYYMMDD>.diff.tgz   # 회전(최신 N개), 삭제목록 포함 매니페스트
│   └── updates.json                # rev/changelog/files/deletes/baseRev(E4)
│
├── libs/                           # crownyc/libs·인증판정·세션이관·커밋체인 심볼릭
├── public/                         # 대시보드(세션/구독상태) — 기존 보존+확장
├── legacy/                         # (보류) KPS 확인 후에만 admin-server 이동
└── runbook/배선.md                 # 포트할당·게이트웨이·LaunchAgent·cert (신규파일만)


3. 한선씨 모듈 함수 시그니처 (확정)

core/엔진서버.한선 — API(:신규포트), lib import만.

  • 엔드포인트: POST /api/signup|login(회원클라이언트 위임), GET /api/me, GET /api/subscription POST /api/subscribe POST /api/subscription/resume, POST /api/run(세션대장 기록+해석된 model/effort 반환, 게이트 아님), GET /api/setting-bundle?tier=(메타데이터 JSON만, tgz 경로 반환), GET /api/packages GET /api/update-check?rev=, GET /api/chain GET /api/chain/verify, GET /setup /cli.
  • VM함정: Connection: close+Content-Length 생략(한글본문), "\r" 금지(마지막 \n 뒤 body), 소켓받기(소켓,최대길이) 2인자, 소켓생성 2인자, 체계() stdout 캡처 불가→>/tmp/x.<pid>읽기().
  • 정산은 여기서 안 함(A2). 폴카운터 폐기.
core/정산.한선 (신규, 크론 진입점, 단일 라이터)
함수 정산_사이클() → 정수                         ; 전체 구독 순회(샤딩, C1), 처리건수
함수 정산_누락월(마지막월키, 현재월키) → 월키목록   ; E6 catch-up
함수 정산_1건(소유자, 월키) → 1/0                 ; bank 차감 위임+overdue/paused 분기
함수 정산_overdue처리(소유자, overdueSince, 현재) → 상태  ; E1 day30 paused
flock으로 엔진서버 지갑변이와 상호배제.

core/구독게이트.한선 (구독판정.한선 참조+확장분만)

함수 구독게이트_판정(잔고, 월비용) → 1(active차감)/0(overdue마킹)/-1(무효)
함수 구독게이트_연체단계(연체일) → 1(day1)/2(day14)/9(day30정지)   ; 절단일수
함수 구독게이트_정지여부(상태) → 1/0
함수 구독게이트_재개판정(잔고, 월비용) → 1/0
(잔고/차감은 구독게이트가 안 함 → 과금클라이언트 위임)

core/과금클라이언트.한선 (B1 — bank 호출, 자체지갑 폐기)

함수 과금_잔고(소유자, 통화) → 정수               ; 체계()+curl -m 5 bank /api/balance, >/tmp 후 읽기
함수 과금_차감(소유자, 통화, 금액, 멱등키, 메모) → 1/0/-1(부족)  ; bank /api/debit, 멱등키 전달
함수 과금_입금(소유자, 통화, 금액, 메모) → 1/0    ; bank /api/credit
외부호출 recv 타임아웃 없음 → 체계()+curl -m 5. 멱등키=bank에서도 중복차감 차단.

core/회원클라이언트.한선 (B2)

함수 회원_가입(ID, 추천인) → 1/0                 ; 회원서비스 /api/signup 위임
함수 회원_존재(ID) → 1/0
함수 회원_조회(ID) → 맵
함수 회원_매핑저장(OS유저, 회원ID) → 1            ; usermap.json (덧쓰기/원자)

core/환율클라이언트.한선 (B5) — 환율_조회(원통화,대상통화)→비율(dex /api/rate), 환전_실행(소유자,원,대상,금액)→1/0(dex /api/swap). 자체 FX 상수 없음.

core/체인.한선 (F1 단일 체인 통합)

함수 체인_블록해시(이전해시, TX데이터, 높이) → 해시   ; SHA256(높이:이전해시:TX)
함수 체인_추가(TX데이터) → 갱신체인                  ; 덧쓰기(wal.log), 3블록 확정
함수 체인_검증() → 1/0                             ; prevHash 체이닝
함수 체인_배치앵커() → 정수                         ; F2: 미앵커 블록 묶음 9729 전송(daily)
함수 체인_TX과금(소유자, 금액, 월키) → "sub:..."
함수 체인_TX빌드(rev, 변경수) → "build:..."
함수 체인_TX정지(소유자, 월키) → "suspend:..."     ; 불변 감사로그(gap#7)
앵커 /tmp 고유경로(C4), curl -m 5(외부 타임아웃).

core/시간헬퍼.한선 (C2 — 절단 SSOT)

함수 절단나눗셈(a, b) → 정수                       ; 자연반올림 회피
함수 월키(에폭초) → "YYYY-MM"                      ; 절단 기반
함수 일수(시작초, 끝초) → 정수                      ; 절단나눗셈(차, 86400)

core/분업라우팅.한선분업_모델선택(작업유형)→"opus"/"sonnet"/"haiku"/"fable"(분업규칙.psv 참조), 분업_모델ID(모델,컨텍스트)→모델문자열, 분업_스로틀티어(모델)→티어.

core/effort판정.한선effort_레벨검증(s), effort_쿼리오버라이드(세션,쿼리), effort_예산(레벨)→정수(실 CLI 플래그 검증 후 매핑, F3).

core/세션제목.한선제목_도출(첫프롬프트)→제목(글자수상한 40), 제목_슬러그(제목), 제목_변경(세션ID,새제목)→1. 문자열: 글자수≠바이트, 분리(...,"\n").

core/패키지빌드판정.한선 (E4 삭제목록·base핀 추가)

함수 빌드_현재rev(updates) → 정수
함수 빌드_파일해시(경로) → 해시                     ; 읽기()+SHA256
함수 빌드_diff대상(이전해시맵, 현재파일목록) → 변경파일문자열  ; 동일해시 제외
함수 빌드_삭제목록(이전파일목록, 현재파일목록) → 삭제문자열    ; E4
함수 빌드_멱등키(날짜) → "YYYYMMDD"
함수 빌드_baseRev핀(updates) → 정수                ; 클라 검증용

core/매니페스트.한선매니페스트_파싱(psv), 매니페스트_번들대상(등급레벨,티어)(학습DB 제외, E5), 매니페스트_시크릿마스킹(등급,경로). 파일목록=문자열→분리.


4. 기존 자산 재사용 (확정 — copy→reference/call 전환)

자산방식대상
crowny-ai/인증판정.한선libs 심볼릭+가져오기 (B3)core/인증판정.한선
libs/세션이관.한선libs 심볼릭포터블복원 참조
crowny-cowork/커밋체인.한선참조 패턴 → core/체인.한선 통합 (F1)
crowny-subscribe/구독판정.한선참조+확장분만core/구독게이트.한선
crowny-bank APIHTTP 호출 (B1)과금클라이언트.한선
crowny-data/services/회원계정.한선(가동)HTTP 호출 (B2)회원클라이언트.한선
dex APIHTTP 호출 (B5)환율클라이언트.한선
chain.crowny.org:9729배치 API call (F2)체인_배치앵커
skills/분별/분업규칙.psv, 분업.한선심볼릭 참조 (B3)분업라우팅.한선
crowny-throttle.shCLI call인터랙티브 턴 게이트
crownyc 바이너리+소스번들 동봉(학습DB 제외)부트스트랩
금융/crowny-wallet.한선존재하지 않음 — 인용 삭제
기존 crowny-admin-server.js(9761)무접촉(legacy 이동 보류, B4)KPS 확인 대기
wrap 대상 import 전 top-level 기동문 검증(C3). 회원계정.한선은 가동 서비스 → import 금지, API 호출만.


5. 구독↔bank↔체인↔회원 배선 (2000 CRD/월, 재정의)

[가입] 회원_가입(ID,추천인)[회원서비스]
   → 과금_입금(ID,"CRD",2000,"가입보너스")[bank]
   → 회원_매핑저장(OS유저,ID)
   → 체인_추가(체인_TX("signup:ID"))

[월 정산] com.crowny.engine-settle 크론 → 정산_사이클()  (단일 라이터, flock)
   for 소유자 in 구독목록(샤딩):                          # C1: 맵/범위샤딩
     누락월 = 정산_누락월(lastBilledMonth, 월키(now))     # E6
     for 월키 in 누락월:                                  # E2: 달력월 단일
       잔고 = 과금_잔고(소유자,"CRD")                     # bank SSOT
       판정 = 구독게이트_판정(잔고, 2000)
       ├ 1(active): 과금_차감(소유자,"CRD",2000,멱등키=월키,"engine-pro")   # bank 멱등
       │            → 체인_추가(체인_TX과금(소유자,2000,월키))
       │            → status="active", lastBilledMonth=월키
       └ 0(overdue): status="overdue", overdueSince=now (미설정시)         # E1
                     → 정산_overdue처리: day1경고/day14경고/day30 paused
                     → status="paused" 시 체인_추가(체인_TX정지)            # 불변 감사
   체인_배치앵커()   # F2: 사이클 끝 한 번만 9729 전송

[서버측 가치 게이트] (A1 — 로컬 claude 아님)
   GET /api/setting-bundle, /api/packages, sync, 멀티유저슬롯, 세션대장:
     구독게이트_정지여부(status)==1 → 403 "월 2000 CRD 미지불 — 충전 후 재개"
   claude실행.sh: 게이트 없음. 세션대장 기록만(미구독=대장 미기록, 로컬 실행은 됨)

[재개] 과금_입금(충전)[bank] → POST /api/subscription/resume
   → 구독게이트_재개판정(잔고,2000) → 과금_차감 → status="active"
   → 체인_추가("resume:ID")

핵심: 모든 가치이동은 bank가 집행(엔진은 의도+멱등키만), 모든 과금/정지/재개는 단일 체인 append + daily 배치 9729 앵커(F1/F2), 정산은 단일 라이터 크론(A2/A3), overdue→day30→paused 일원화(E1), 달력월 멱등+누락월 catch-up(E2/E6).


6. 일일 빌드 + 중복제거 (E3/E4/E5/C5 반영)

shell/일일빌드.sh (LaunchAgent com.crowny.engine-dailybuild 매일 10시):

  1. flock data/.build.lock 획득(E3, LaunchAgent+수동 경쟁 차단).
  2. 빌드_멱등키(오늘) — 같은 날 재실행 차단.
  3. 매니페스트_번들대상(등급,티어) → 후보(학습DB 제외, E5).
  4. 빌드_파일해시 → 직전 updates.json 해시맵과 빌드_diff대상 비교. 동일해시 제외.
  5. 빌드_삭제목록(이전↔현재 파일목록 차집합) 계산(E4).
  6. 변경/신규만 daily/<date>.diff.tgz tar(HOME상대). 이전 tgz 미보관, daily만 누적하되 회전(최신 N개)(E5 디스크폭증 차단).
  7. updates.json append: {rev, date, baseRev, changelog, files:[변경], deletes:[삭제]}(E4 base핀).
  8. 체인_추가(체인_TX빌드(rev,변경수)) → 변조방지.
  9. tgz는 data/packages/에 두고 게이트웨이 정적 서빙(A4, 한선씨 바이너리 스트리밍 안 함).
  10. 실행중 .toau 갱신시 /tmp/x.newmv 원자 rename(C5).
  11. 학습DB는 crownycode-learn.sh sync 전용 경로, 번들 무관(E5).
복원: 클라가 update-check?rev=로 baseRev 확인 → base rev 불일치면 새 base 먼저(E4) → 이후 daily diff 순차 + 삭제목록 적용(삭제파일 제거) → rev 갱신.


7. 포터빌리티 (D1/D3 안전화)

  1. 저장 규칙: 전 경로 ~/... HOME상대(절대 /Users/ef 금지), IP 금지(*.crowny.org).
  2. 번들: 일일빌드가 HOME상대 tar(crownyc 소스+skills+core, 학습DB 제외).
  3. 포터블복원.sh <bundle>:
- 싱크체인 해시 서명검증(D1) — 불일치시 중단. - tar --no-absolute-names, ../절대경로 엔트리 거부(D1). - 세션이관.한선 세션복원경로복원(경로, 환경변수("HOME")) 화이트리스트 치환(메타문자 거부). - crownyc arch 불일치 → 동봉 소스로 make 재빌드. - 학습DB는 crownycode-learn.sh sync로 별도 정합(E5).
  1. 부트스트랩.sh: curl|bash 금지 → 다운로드 → 체크섬/서명검증 → 실행(D3).
  2. 멀티유저는 OS 격리 아님(D2) — API per-user 인증+파일권한, 문서 정직 기술.

임계경로 빌드 순서 (무엇을 먼저)

설계 전제를 떠받치는 순서. 적대검토 권고 우선순위(A1→B1/B2→A3→A2→D1→E1/E2)를 빌드 단계로 변환.

  1. [전제 확정·코드 0줄] 통합 지점 검증 — bank API(잔고/차감/입금 엔드포인트+멱등키 지원 여부), 회원서비스 API, dex 환율 API 실제 스펙 확인. crowny-ports.sh free로 엔진 신규포트 할당+set. KPS에 9761 admin-server 용도 확인 요청(음→이관). 이게 안 되면 나머지 전부 가정 위에 지어짐.
  2. 시간헬퍼.한선 + 체인.한선 — 모든 정산·빌드·앵커가 의존하는 토대(절단나눗셈/월키 C2, 단일 체인 F1). 독립 테스트 가능.
  3. 과금클라이언트.한선 + 회원클라이언트.한선 + 환율클라이언트.한선 — B1/B2/B5 외부 위임 계층. bank/회원/dex 모킹으로 검증. (자체 지갑/계정 안 만듦)
  4. 구독게이트.한선 + 정산.한선 — A2(크론 분리)+A3(단일 라이터)+E1(overdue)+E2/E6(달력월·catch-up). 3을 호출. flock 직렬화.
  5. 엔진서버.한선 — 서버측 가치 API(A1 재정의: setting-bundle/packages/sync/슬롯/대장만 게이트). 2~4 import. VM함정 방어.
  6. 패키지빌드판정.한선 + 매니페스트.한선 + 일일빌드.sh — E3(flock)/E4(삭제·base핀)/E5(학습DB제외·회전)/A4(정적서빙)/C5(원자스왑).
  7. **shell/* 더블(.sh+.한선) — claude실행/멀티유저/인터랙티브/세션제목설정. A1대로 게이트 아님, 세션대장+model/effort 해석만. D2 정직기술.
  8. 포터블복원.sh + 부트스트랩.sh — D1(서명검증·안전tar)/D3(체크섬). 마지막(앞 단계 산출물을 번들).
  9. 배선 — runbook/배선.md대로 LaunchAgent 3종(api/settle/dailybuild) 등록, 게이트웨이 정적 경로(packages), cert/stunnel SNI 확인. 라이브 admin-server 무접촉.

이번 스캐폴드에서 만들 파일 목록 (절대경로 + 핵심 함수)

모든 .sh는 동반 .한선 판정부 포함(헌법). 라이브 admin-server/server.js/9761 무접촉. 신규 파일만.

core/ (한선씨 SSOT)

  • /Users/ef/crowny-engine/core/시간헬퍼.한선절단나눗셈(a,b) 월키(에폭초) 일수(시작,끝)
  • /Users/ef/crowny-engine/core/체인.한선체인_블록해시(이전,TX,높이) 체인_추가(TX) 체인_검증() 체인_배치앵커() 체인_TX과금/TX빌드/TX정지
  • /Users/ef/crowny-engine/core/과금클라이언트.한선과금_잔고(소유자,통화) 과금_차감(소유자,통화,금액,멱등키,메모) 과금_입금(소유자,통화,금액,메모) (bank API)
  • /Users/ef/crowny-engine/core/회원클라이언트.한선회원_가입(ID,추천인) 회원_존재(ID) 회원_조회(ID) 회원_매핑저장(OS유저,ID) (회원서비스 API)
  • /Users/ef/crowny-engine/core/환율클라이언트.한선환율_조회(원,대상) 환전_실행(소유자,원,대상,금액) (dex API)
  • /Users/ef/crowny-engine/core/구독게이트.한선구독게이트_판정(잔고,월비용) 구독게이트_연체단계(연체일) 구독게이트_정지여부(상태) 구독게이트_재개판정(잔고,월비용)
  • /Users/ef/crowny-engine/core/정산.한선정산_사이클() 정산_누락월(마지막월키,현재월키) 정산_1건(소유자,월키) 정산_overdue처리(소유자,overdueSince,현재)
  • /Users/ef/crowny-engine/core/엔진서버.한선처리_요청(경로,메서드,바디) 라우트_구독/지갑/패키지/체인/세션 응답_보내기(소켓,상태,JSON) (Content-Length 생략·"\r"금지·소켓받기 2인자)
  • /Users/ef/crowny-engine/core/분업라우팅.한선분업_모델선택(작업유형) 분업_모델ID(모델,컨텍스트) 분업_스로틀티어(모델)
  • /Users/ef/crowny-engine/core/effort판정.한선effort_레벨검증(s) effort_쿼리오버라이드(세션,쿼리) effort_예산(레벨)
  • /Users/ef/crowny-engine/core/세션제목.한선제목_도출(첫프롬프트) 제목_슬러그(제목) 제목_변경(세션ID,새제목)
  • /Users/ef/crowny-engine/core/패키지빌드판정.한선빌드_현재rev(u) 빌드_파일해시(경로) 빌드_diff대상(이전해시맵,현재목록) 빌드_삭제목록(이전,현재) 빌드_멱등키(날짜) 빌드_baseRev핀(u)
  • /Users/ef/crowny-engine/core/매니페스트.한선매니페스트_파싱(psv) 매니페스트_번들대상(등급,티어) 매니페스트_시크릿마스킹(등급,경로)
shell/ (.sh + 동반 .한선)
  • /Users/ef/crowny-engine/shell/claude실행.sh + .한선 — (.한선) 실행_모델해석(세션,쿼리,작업유형) 실행_effort해석(세션,쿼리) 실행_인자조립(모델ID,effort,사용자) 실행_세션기록판정(구독상태)
  • /Users/ef/crowny-engine/shell/멀티유저.sh + .한선 — (.한선) 유저_슬롯배정(사용자ID) 유저_격리경로(사용자)(HOME상대) 유저_인증판정(사용자,토큰)
  • /Users/ef/crowny-engine/shell/인터랙티브.sh + .한선 — (.한선) 턴_파싱(입력)→(종류,값) 턴_라우팅(종류,세션상태)→액션 (:model/:effort/:title/:user/:sub/:q)
  • /Users/ef/crowny-engine/shell/세션제목설정.shset/rename → 제목_도출/제목_변경 호출, 대장+LIVE_STATUS 반영
  • /Users/ef/crowny-engine/shell/일일빌드.sh + .한선 — (.sh) flock+tar+mv원자; (.한선) 빌드_실행판정() 빌드_tar대상(파일목록)
  • /Users/ef/crowny-engine/shell/정산기동.sh — 크론 래퍼 → crownyc run 정산.toau
  • /Users/ef/crowny-engine/shell/포터블복원.sh — 서명검증+tar --no-absolute-names+엔트리거부+경로복원
  • /Users/ef/crowny-engine/shell/부트스트랩.sh — 다운로드→체크섬검증→설치(curl|bash 금지)
bin/
  • /Users/ef/crowny-engine/bin/crowny-engine — PATH 런처 → 엔진.sh
  • /Users/ef/crowny-engine/bin/엔진서버기동.sh(nohup crownyc run /tmp/엔진서버.toau >log 2>&1 </dev/null &)
최상위
  • /Users/ef/crowny-engine/엔진.sh — 디스패처 run/user/model/sub/pkg/sync/serve/title
  • /Users/ef/crowny-engine/CLAUDE.md — 패키지 규칙+VM함정+서브에이전트 가드레일(~/.claude/templates/한선씨-가드레일.md 주입)
  • /Users/ef/crowny-engine/package.json — @crowny/engine, deps @crowny/crownyc ^10.3
  • /Users/ef/crowny-engine/README.md — 부트스트랩 한 줄
  • /Users/ef/crowny-engine/runbook/배선.md — 신규포트 할당, LaunchAgent 3종(api/settle/dailybuild), 게이트웨이 packages 정적경로, cert/stunnel SNI, 9761 admin-server 무접촉+KPS 확인 메모
data/ (초기 설정 파일)
  • /Users/ef/crowny-engine/data/plans.jsonengine-pro: {price:2000, currency:"CRD", period:"month"}
  • /Users/ef/crowny-engine/data/tier-manifest.psv — 번들 SSOT(crownyc 소스행, 학습DB 행 없음)
  • /Users/ef/crowny-engine/data/updates.json{rev, baseRev, history:[]} 초기 골격
심볼릭(물리 copy 금지, B3)
  • /Users/ef/crowny-engine/libs/인증판정.한선 → crowny-ai 정본
  • /Users/ef/crowny-engine/libs/세션이관.한선 → libs 정본
  • /Users/ef/crowny-engine/data/분업규칙.psv → skills/분별 정본
보류(만들지 않음, KPS 확인 대기): legacy/ 이동 — 9761 admin-server는 라이브 가능성 있어 무접촉.


적대검토 원본

Verification done. Key facts confirmed: 9761 is registered in gateway.yaml (line 2092+) and currently dead (curl→000), the stub's server.js does bind 9761, but the stub is
not a "game-engine landing" — crowny-admin-server.js exposes /api/admin/requests (an admin request-tracking API). The cited wallet asset 금융/crowny-wallet.한선 does not exist; real wallet/money sources are scattered across crowny-wallet/, crowny-finance/, crowny-bank/, crowny-data/services/. Other cited assets exist.


적대 검토: 크라우니엔진 아키텍처 초안

A. 치명적 아키텍처 결함 (먼저 봐야 함)

A1 [높음] 로컬 claude 바이너리는 구독게이트로 막을 수 없다 — 페이월 전체가 우회 가능 게이트가 claude실행.sh 안에서 서버에 질의해 차단하는 구조인데, 그 셸 스크립트와 claude 바이너리는 사용자 자기 머신에서 사용자 자기 Anthropic 인증으로 돈다. 사용자가 claude를 래퍼 없이 직접 부르거나 model.cfg를 편집하면 2000 CRD를 안 내고 그대로 쓴다. 게이트는 강제가 아니라 권고일 뿐이다. → 수정**: 구독은 서버가 쥔 가치에만 걸어라 — 일일패키지 다운로드, 학습DB sync, 블록체인 앵커, 멀티유저 슬롯, 세션 대장. 로컬 claude 실행 자체를 페이월하려면 서버가 API 키를 브로커링/프록시해야 한다(설계에 없음). 현 구조면 "구독" 문구를 정직하게 "서버측 협업 서비스 구독"으로 재정의하라.

A2 [높음] 자동정산 폴이 HTTP accept 루프에 묶여 있어 트래픽 없으면 과금이 영영 안 돈다 "메인 루프 폴카운터(소켓폴링 100ms×N)마다 정산사이클" — 한선씨 VM의 소켓수락/소켓받기타임아웃이 없어 연결이 올 때까지 블록된다. 따라서 정산은 타이머가 아니라 "다음 요청이 들어올 때"만 발화한다. 무트래픽 구간엔 월 정산이 누락된다. → 수정: 정산을 별도 LaunchAgent 크론(com.crowny.engine-settle, 정산.한선 배치)으로 분리. 인-루프 타이머 가정 폐기. 요청마다 nextBillAt 과거스캔 catch-up은 보조로만.

A3 [높음] 지갑 이중지불 TOCTOU — 잔고 읽고→검사→쓰기가 프로세스 간 비원자 지갑_차감이 잔고 읽기→부족검사→쓰기인데, 매 턴 claude실행.sh//api/run/정산이 동시에 같은 subscriptions.json·ledger.jsonl을 건드린다. 한선씨 쓰기()는 전체 파일 덮어쓰기(append 아님)라 동시 쓰기 = 분실 갱신 또는 이중차감. 멱등 월키는 월 정산 중복만 막고, 재개 차감·동시 충전엔 무력. → 수정: 모든 지갑 변이를 엔진서버 단일 라이터로 직렬화. .sh는 절대 원장에 직접 쓰지 말고 API 경유. 잔고는 캐시 필드가 아니라 원장 합(sum of ledger)을 SSOT로. 원장 추가는 쓰기가 아니라 덧쓰기()(append).

A4 [높음] 번들/패키지 tgz를 한선씨 문자열 경로로 서빙 — 바이너리 깨짐 /api/setting-bundle, /api/packages가 tgz(바이너리, null 포함)를 반환하는데 한선씨 소켓쓰기+글자수 길이로 보내면 글자수≠바이트 + null 절단으로 손상된다(메모리 feedback_hanseon_binary_zip_docx 경고). → 수정: tgz는 게이트웨이/정적 파일 경로로 직접 서빙하거나 외부 도구로 전송. 한선씨 문자열 연산으로 바이너리 스트리밍 금지.

B. 기존 자산 오용

B1 [높음] 금융/crowny-wallet.한선은 존재하지 않음 + 화폐 SSOT 위반 실제 지갑은 crowny-wallet/지갑서버.한선, crowny-finance/src/지갑.한선, crowny-bank/web/wallet.한선, crowny-data/services/wallet.한선경쟁 구현 다수. 헌법상 화폐=chain/bank/dex가 SSOT인데 엔진이 자체 지갑.한선+원장을 임베드하면 bank 잔고와 갈라진다. → 수정: 엔진은 자체 지갑을 만들지 말고 crowny-bank API를 호출. 어느 게 화폐 정본인지 먼저 확정.

B2 [높음] 회원 DB 포크 — 회원계정.한선은 이미 가동 서비스(crowny-data/services) copy+wrap하면 엔진 accounts.json과 라이브 회원 서비스가 분기해 같은 사용자가 두 상태를 갖는다. → 수정: 기존 회원 서비스를 호출(reference), 별도 계정 저장 금지.

B3 [중간] "copy"가 SSOT를 깨뜨린다 인증판정·세션이관·싱크체인·분업규칙을 core/로 copy한다고 했는데, 메모리상 crowny-ai/인증판정.한선공유 SSOT다. 복사 = 드리프트. → 수정: libs/ 심볼릭으로 정본을 가져오기(참조), 물리 복사 금지.

B4 [중간] stub 성격 오판 초안 서두 "non-live game-engine landing stub"은 부정확 — 실제로 /api/admin/requests 관리 API(crowny-admin-server.js)다. legacy 이동 시 다른 곳의 admin 흐름이 깨질 수 있다. KPS 확인(음→이관) 명시는 옳으나, 설계는 "안전하다" 전제로 진행 중. 확인 전 legacy 이동 보류.

B5 [중간] 환율 자체발명 (1 CRN=1000 CRD, 환전 7%) 환율은 dex가 SSOT. 엔진이 FX를 임베드하면 dex와 불일치.

C. 한선씨 VM 함정

C1 [중간] 6561 슬롯풀 vs 배열 1023 silent 상한 회원_에이전트배정 6561 슬롯을 단일 한선씨 배열에 담으면 1023에서 조용히 잘린다. 같은 문제가 정산사이클의 사용자/구독 순회에도 적용 — 사용자 >1023이면 일부가 과금 누락(=무료). → 수정: 슬롯/사용자는 맵 또는 범위샤딩. 6561은 과설계 허영수(C가 아니라 #과설계 참조).

C2 [중간] 일수/월키 나눗셈 자연반올림 초/86400 일수계산이 ceil 경향이라 day14/day30 grace가 하루 일찍 발화. 초안 "절단헬퍼" 언급은 좋으나 월키 YYYY-MM epoch 환산에도 반드시 절단 적용 명시 필요.

C3 [중간] 가져오기 side-effect 블록체인.한선·회원계정.한선(가동 서비스)에 top-level 기동문이 있으면 import가 그걸 실행. 초안 *_lib.한선 추출안은 옳음 — 단 각 대상 실제 검증 필요(나는 블록체인.한선엔 명백한 루프 미발견했으나 회원계정.한선은 서비스 디렉토리라 위험).

C4 [낮음] 앵커_원격 /tmp 경쟁 체계()+curl >/tmp 후 읽기() 패턴은 옳으나 동시 앵커가 같은 /tmp를 덮어씀 → 고유 tmp(pid/height).

C5 [낮음] 실행중 .toau 교체 /tmp/엔진서버.toau 교체 시 cp는 손상(메모리 feedback_running_binary_atomic_swap) → mv 원자 rename. 초안 미언급.

D. 보안 — 경로주입·격리

D1 [높음] 포터블 복원 경로주입 tar xzf -C $HOME은 tar 엔트리에 절대경로/../가 있으면 HOME 밖으로 임의 파일 쓰기/덮어쓰기. 신뢰 안 되는 번들이 임의 파일 변조. → 수정: tar --no-absolute-names, ../절대경로 엔트리 거부, 추출 전 싱크체인 해시로 번들 서명검증(이미 해시 있음). 경로복원의 "~" 문자열 치환도 저장경로에 메타문자 있으면 주입 — 화이트리스트 검증.

D2 [중간] 멀티유저는 격리가 아니라 네임스페이싱 전부 같은 OS 유저(ef) 아래 → ledger.jsonl/session.json 상호 열람 가능. "격리" 표현은 과장. → 수정: API에 per-user 인증 강제 + 파일 권한. 또는 문서에서 "격리 아님" 정직 기술.

D3 [중간] 부트스트랩 curl|bash TLS+체크섬 검증 없이 curl|bash. 메모리상 stunnel SNI 000 재발 이력 → MITM 시 임의 코드. 최소 체크섬/서명 검증.

E. 빠진 엣지케이스

E1 [중간] grace period 자기모순 정산사이클이 음(9)에서 즉시 status=paused(day0)인데 연체단계는 day1/14/30을 말함. grace가 실존하나? → 잔고부족 시 active-but-overdue로 두고 day30에 paused로 일원화. 안 그러면 grace는 허구.

E2 [중간] 두 과금 주기 모델 혼용 멱등키는 YYYY-MM(달력월), nextBillAt은 +30d(롤링). 월 경계에서 이중과금 또는 누락. 하나만 골라라. 가입 2000 보너스 + 즉시 월정산이면 가입월 처리(첫달 무료/즉시차감) 규칙 미정.

E3 [중간] 일일빌드 동시실행 경쟁 빌드_멱등키는 read→decide→write 자체가 lock 없이 경쟁(LaunchAgent + 수동 동시). → flock 락파일 + 원자 rev 증가.

E4 [중간] diff 복원 정확성 — 삭제 불가 "base + 모든 daily diff 순차" 모델에서 tar diff는 추가/덮어쓰기만 표현 → 삭제된 파일이 클라에 영원히 잔존. 또 클라가 새 base 갱신을 놓치고 옛 diff를 잘못된 base에 적용하면 손상. → 수정: diff 매니페스트에 삭제목록 + diff마다 base-rev 핀, 클라가 base rev 검증 후 적용.

E5 [중간] 학습.dat가 dedup을 무력화 + 디스크 재폭증 27MB 라인지향 바이너리가 매 세션 변동 → 사실상 매일 27MB 전체 동봉(tar는 델타 아님). 메모리 feedback_learn_db_backup_rotation: 학습.dat 무회전 백업이 30G 볼륨포화 일으킨 전력. daily/ 누적이 같은 재앙. → 수정: 학습DB는 패키지 번들에서 빼고 crownycode-learn.sh sync 전용 경로로. daily/에 회전 정책 강제.

E6 [낮음] 클럭 점프 시 월 스킵 월키 멱등이라 클럭이 한 달 건너뛰면 그 달은 "이미 됨"으로 오인돼 영영 미과금. → lastBilledMonth~now 사이 누락 월 전부 순회 과금.

F. 과설계

F1 [중간] 이중 체인블록체인앵커.한선(블록체인 wrap) + 싱크체인.한선(커밋체인 copy) 두 해시체인이 감사/빌드싱크로 중복. 하나의 체인 추상으로 통합.

F2 [낮음] 구독 차감마다 9729 원격앵커 — 사용자당 연 12건을 매번 원격앵커하면 매 정산이 외부 의존+지연. → daily 배치앵커, 또는 분쟁/정지만 앵커.

F3 [낮음] 6561 슬롯·effort→maxThinkingTokens — 6561은 허영수(C1 충돌). effort low/medium/high/max를 raw 토큰예산 env로 주입한다는 가정은 현 claude CLI와 안 맞을 수 있음 → 실제 플래그 검증 후 매핑.


종합 판정

초안은 VM 함정 인지는 매우 우수(Content-Length 생략, "\r" 금지, 소켓 2인자, 체계 stdout, 절단헬퍼 등 선제 방어). 그러나 세 가지 근본 결함이 설계 전제를 무너뜨린다: (1) A1 로컬 claude는 페이월 불가 — 구독 가치 모델 재정의 필요, (2) A2 정산 타이머가 accept 루프에 묶여 무트래픽 시 미발화, (3) B1/B2 지갑·회원을 자체 포크(존재하지 않는 경로 인용 포함)해 화폐/회원 SSOT 위반.

권고 우선순위: A1(구독 재정의) → B1/B2(bank·회원 서비스 호출로 전환) → A3(단일 라이터 직렬화) → A2(크론 분리) → D1(번들 서명+tar 안전추출) → E1/E2(grace·과금주기 일원화). 나머지는 그 위에서 정리.

검토 근거 파일: /Users/ef/crowny-gateway/gateway.yaml:2092, /Users/ef/crowny-engine/server.js:6, /Users/ef/crowny-engine/crowny-admin-server.js:94, 실재 지갑들 /Users/ef/crowny-wallet/지갑서버.한선·/Users/ef/crowny-finance/src/지갑.한선·/Users/ef/crowny-bank/web/wallet.한선, 회원 /Users/ef/crowny-data/services/회원계정.한선.