크라우니엔진 아키텍처
크라우니엔진 (@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/subscriptionPOST /api/subscribePOST /api/subscription/resume,POST /api/run(세션대장 기록+해석된 model/effort 반환, 게이트 아님),GET /api/setting-bundle?tier=(메타데이터 JSON만, tgz 경로 반환),GET /api/packagesGET /api/update-check?rev=,GET /api/chainGET /api/chain/verify,GET /setup/cli. - VM함정:
Connection: close+Content-Length 생략(한글본문),"\r"금지(마지막\n뒤 body),소켓받기(소켓,최대길이)2인자,소켓생성2인자,체계()stdout 캡처 불가→>/tmp/x.<pid>후읽기(). - 정산은 여기서 안 함(A2). 폴카운터 폐기.
함수 정산_사이클() → 정수 ; 전체 구독 순회(샤딩, 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 API | HTTP 호출 (B1) | 과금클라이언트.한선 |
| crowny-data/services/회원계정.한선(가동) | HTTP 호출 (B2) | 회원클라이언트.한선 |
| dex API | HTTP 호출 (B5) | 환율클라이언트.한선 |
| chain.crowny.org:9729 | 배치 API call (F2) | 체인_배치앵커 |
| skills/분별/분업규칙.psv, 분업.한선 | 심볼릭 참조 (B3) | 분업라우팅.한선 |
| crowny-throttle.sh | CLI call | 인터랙티브 턴 게이트 |
| crownyc 바이너리+소스 | 번들 동봉(학습DB 제외) | 부트스트랩 |
| 존재하지 않음 — 인용 삭제 | — | |
| 기존 crowny-admin-server.js(9761) | 무접촉(legacy 이동 보류, B4) | KPS 확인 대기 |
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시):
- flock
data/.build.lock획득(E3, LaunchAgent+수동 경쟁 차단). 빌드_멱등키(오늘)— 같은 날 재실행 차단.매니페스트_번들대상(등급,티어)→ 후보(학습DB 제외, E5).빌드_파일해시→ 직전updates.json해시맵과빌드_diff대상비교. 동일해시 제외.빌드_삭제목록(이전↔현재 파일목록 차집합) 계산(E4).- 변경/신규만
daily/<date>.diff.tgztar(HOME상대). 이전 tgz 미보관, daily만 누적하되 회전(최신 N개)(E5 디스크폭증 차단). updates.jsonappend:{rev, date, baseRev, changelog, files:[변경], deletes:[삭제]}(E4 base핀).체인_추가(체인_TX빌드(rev,변경수))→ 변조방지.- tgz는
data/packages/에 두고 게이트웨이 정적 서빙(A4, 한선씨 바이너리 스트리밍 안 함). - 실행중 .toau 갱신시
/tmp/x.new→mv원자 rename(C5). - 학습DB는
crownycode-learn.sh sync전용 경로, 번들 무관(E5).
update-check?rev=로 baseRev 확인 → base rev 불일치면 새 base 먼저(E4) → 이후 daily diff 순차 + 삭제목록 적용(삭제파일 제거) → rev 갱신.7. 포터빌리티 (D1/D3 안전화)
- 저장 규칙: 전 경로
~/...HOME상대(절대/Users/ef금지), IP 금지(*.crowny.org). - 번들: 일일빌드가 HOME상대 tar(crownyc 소스+skills+core, 학습DB 제외).
포터블복원.sh <bundle>:
tar --no-absolute-names, ../절대경로 엔트리 거부(D1).
- 세션이관.한선 세션복원 → 경로복원(경로, 환경변수("HOME")) 화이트리스트 치환(메타문자 거부).
- crownyc arch 불일치 → 동봉 소스로 make 재빌드.
- 학습DB는 crownycode-learn.sh sync로 별도 정합(E5).
부트스트랩.sh: curl|bash 금지 → 다운로드 → 체크섬/서명검증 → 실행(D3).- 멀티유저는 OS 격리 아님(D2) — API per-user 인증+파일권한, 문서 정직 기술.
임계경로 빌드 순서 (무엇을 먼저)
설계 전제를 떠받치는 순서. 적대검토 권고 우선순위(A1→B1/B2→A3→A2→D1→E1/E2)를 빌드 단계로 변환.
- [전제 확정·코드 0줄] 통합 지점 검증 — bank API(잔고/차감/입금 엔드포인트+멱등키 지원 여부), 회원서비스 API, dex 환율 API 실제 스펙 확인.
crowny-ports.sh free로 엔진 신규포트 할당+set. KPS에 9761 admin-server 용도 확인 요청(음→이관). 이게 안 되면 나머지 전부 가정 위에 지어짐. - 시간헬퍼.한선 + 체인.한선 — 모든 정산·빌드·앵커가 의존하는 토대(절단나눗셈/월키 C2, 단일 체인 F1). 독립 테스트 가능.
- 과금클라이언트.한선 + 회원클라이언트.한선 + 환율클라이언트.한선 — B1/B2/B5 외부 위임 계층. bank/회원/dex 모킹으로 검증. (자체 지갑/계정 안 만듦)
- 구독게이트.한선 + 정산.한선 — A2(크론 분리)+A3(단일 라이터)+E1(overdue)+E2/E6(달력월·catch-up). 3을 호출. flock 직렬화.
- 엔진서버.한선 — 서버측 가치 API(A1 재정의: setting-bundle/packages/sync/슬롯/대장만 게이트). 2~4 import. VM함정 방어.
- 패키지빌드판정.한선 + 매니페스트.한선 + 일일빌드.sh — E3(flock)/E4(삭제·base핀)/E5(학습DB제외·회전)/A4(정적서빙)/C5(원자스왑).
- **shell/* 더블(.sh+.한선) — claude실행/멀티유저/인터랙티브/세션제목설정. A1대로 게이트 아님, 세션대장+model/effort 해석만. D2 정직기술.
- 포터블복원.sh + 부트스트랩.sh — D1(서명검증·안전tar)/D3(체크섬). 마지막(앞 단계 산출물을 번들).
- 배선 — runbook/배선.md대로 LaunchAgent 3종(api/settle/dailybuild) 등록, 게이트웨이 정적 경로(packages), cert/stunnel SNI 확인. 라이브 admin-server 무접촉.
이번 스캐폴드에서 만들 파일 목록 (절대경로 + 핵심 함수)
모든.sh는 동반.한선판정부 포함(헌법). 라이브 admin-server/server.js/9761 무접촉. 신규 파일만.
core/ (한선씨 SSOT)
shell/ (.sh + 동반 .한선)
/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) 매니페스트_번들대상(등급,티어) 매니페스트_시크릿마스킹(등급,경로)
bin/
/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/세션제목설정.sh — set/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 금지)
최상위
/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 &)
data/ (초기 설정 파일)
/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 확인 메모
학습DB 행 없음)
/Users/ef/crowny-engine/data/plans.json — engine-pro: {price:2000, currency:"CRD", period:"month"}/Users/ef/crowny-engine/data/tier-manifest.psv — 번들 SSOT(crownyc 소스행, /Users/ef/crowny-engine/data/updates.json — {rev, baseRev, history:[]} 초기 골격
보류(만들지 않음, KPS 확인 대기): /Users/ef/crowny-engine/libs/인증판정.한선 → crowny-ai 정본/Users/ef/crowny-engine/libs/세션이관.한선 → libs 정본/Users/ef/crowny-engine/data/분업규칙.psv → skills/분별 정본legacy/ 이동 — 9761 admin-server는 라이브 가능성 있어 무접촉.
적대검토 원본
Verification done. Key facts confirmed: 9761 is registered in gateway.yaml (line 2092+) and currently dead (curl→000), the stub'sserver.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/회원계정.한선.