Skip to content

feat(bridge): keep editor plumbing out of player builds - #183

Merged
yhc509 merged 1 commit into
devfrom
feat/release-build-hardening
Aug 15, 2026
Merged

yhc509 merged 1 commit into
devfrom
feat/release-build-hardening

Conversation

@yhc509

@yhc509 yhc509 commented Aug 14, 2026

Copy link
Copy Markdown
Owner

배경

릴리즈(플레이어) 빌드 관점에서 패키지를 점검한 결과, 빌드를 깨뜨리는 요소는 없었지만 네 가지 실질 리스크가 있었다. 이 PR은 그중 패키지 쪽 세 가지를 고친다.

무엇이 문제였나

1. Runtime 어셈블리에 에디터 전용 인프라가 섞여 플레이어로 나갔다.

Runtime asmdef 하나가 두 가지를 함께 담고 있었다 — 게임이 의도적으로 참조하는 QA 마커 4파일(96줄)과, Runtime/Protocol/ 전체(26파일 6,315줄: 인스턴스 레지스트리 파일 I/O, chmod용 Process.Start, CLI 설치 경로 해석, 전체 커맨드 카탈로그와 한글 헬프 텍스트). includePlatforms: []라 전부 플레이어 빌드로 컴파일됐다. 도달 불가능한 코드지만 managed stripping Low에서 제거는 보장되지 않고, 남으면 출시 바이너리에 strings로 CLI 툴링 메타데이터가 드러난다.

2. CI/배치모드 빌드 잡에서도 브릿지가 자동 기동됐고, 끄는 방법이 없었다.

BridgeHost[InitializeOnLoad]이고 제외 조건은 MPE/-adb2 보조 프로세스뿐이라, 플레이어를 뽑으려고 띄운 헤드리스 에디터도 소켓을 바인드하고 레지스트리 엔트리 + 토큰 sidecar를 만들었다. 병렬 빌드에서는 레지스트리 락 경합이 생기고, 리스너 watchdog이 실패 시 5초×5회 재시도하며 LogError를 남겨 빌드 로그를 오염시킨다.

3. Unity Recorder가 하드 의존이었다.

record 명령군과 qa run-sequence --record만 쓰는데 모든 소비 프로젝트가 Recorder(+Timeline)를 받았다.

변경 내용

Protocol을 Editor 전용 어셈블리로 분리Runtime/Protocol/에 자체 asmdef(includePlatforms: ["Editor"], autoReferenced: false)를 추가했다. 파일 위치는 그대로라 CLI의 <Compile Include> 링크와 shared-protocol 위치 가드는 손대지 않았다.

브릿지 킬스위치UNITY_CLI_BRIDGE_DISABLE(0/false/빈 값 외 아무 값) 또는 -noUnityCliBridge 에디터 플래그. BridgeBootstrap이 호스트를 생성조차 하지 않는다 — 세션 락 복원도, 레지스트리 등록도, 토큰 sidecar도, update 훅도 없다. 파싱은 Runtime/Protocol/BridgeDisableSwitch.cs에 두어 유닛 테스트했고, 체크가 new BridgeHost()보다 먼저 실행되는지는 소스 순서 테스트로 고정했다.

Recorder optional화versionDefinescom.unity.recorderUNITY_CLI_BRIDGE_RECORDER를 매핑하고 Recorder API 접점을 전부 가드했다. record start는 메모리 프로파일러 게이트와 같은 형태로 설치 안내를 돌려주고, record stop/record status는 기존 sidecar를 계속 서빙한다.

com.unity.test-framework를 명시 의존으로 선언 — 아래 "발견" 참조.

검증에서 드러난 사실 2건

Unity는 없는 asmdef 참조를 에러가 아니라 무시한다. Input System 미설치 프로젝트에서 Editor 어셈블리가 정상 컴파일되는 것으로 먼저 확인했고, 참조가 조용히 드롭된 뒤 해당 타입을 쓰는 코드에서 CS0246이 나는 구조였다. 그래서 optional 패키지는 asmdef references 항목을 유지한 채 모든 API 접점을 define으로 감싸는 두 절반이 다 필요하다.

com.unity.test-framework가 Recorder를 통해 전이로 딸려오고 있었다. Recorder 의존을 떼자 최소 구성 프로젝트에서 TestCommandHandler/TestRunnerCallbacksITestAdaptor/TestMode/TestRunnerApi를 못 찾아 컴파일이 깨졌다. 테스트 핸들러는 TestRunnerApi 타입을 가드 없이 쓰므로 실제 필수 의존이 맞고, 이제 package.json에 직접 선언한다.

라이브 검증

Unity 6000.3.10f1 / file: UPM 참조 프로젝트에서 실측:

  • CompilationPipeline.GetAssemblies(AssembliesType.Player)[UnityCliBridge.Bridge.Runtime] 하나. Editor 쪽은 [Protocol, Editor, Runtime].
  • 플레이어 대상 어셈블리 157,792 B → 7,168 B (Protocol 154,624 B가 빠짐).
  • -noUnityCliBridge로 띄운 에디터: 로그에 disable 한 줄, instances list에 미등록, 토큰 sidecar 없음, 소켓 파일 없음. 프로세스는 정상 동작.
  • Recorder 미설치 상태에서 record startRECORD_FAILED + 설치 안내.
  • test list 정상 응답(신규 선언한 test-framework 경유), read-console --type error 비어 있음.

.meta는 Unity가 생성했고 scripts/check-unity-meta.sh 통과.

테스트

dotnet test 1057 green (신규 24건). ReleaseBuildSurfaceTests가 플레이어 노출면을 고정한다 — asmdef과 package.json은 어떤 컴파일러도 검증하지 않는 JSON이라, 한 글자 수정으로 Protocol이 다시 출시 빌드에 들어갈 수 있다.

다루지 않은 것

  • 소비 프로젝트의 #main — 이 리포 밖의 일이라 별도 처리.
  • Recorder 사용자 영향 — 기존 사용자가 업그레이드하면 Recorder가 전이 의존에서 빠지므로 record를 쓰려면 com.unity.recorder를 직접 추가해야 한다. 릴리즈 노트에 명시 필요.
  • com.unity.test-framework 버전 하한 1.4.5 — Unity 2023.1+ 레지스트리 기준으로 잡았고, 더 높은 버전을 요구하는 프로젝트에서는 UPM이 높은 쪽으로 해석한다.

🤖 Generated with Claude Code

The package shipped one runtime assembly holding both the four QA marker
types a game references on purpose and the whole Runtime/Protocol tree —
registry file I/O, Process.Start for chmod, the full command catalog and
its help text. All of it compiled into player builds as unreachable code.

Protocol now carries its own Editor-only asmdef. It stays under Runtime/
because the CLI links the same sources, but CompilationPipeline confirms
the player set is down to the marker assembly alone (158 KB -> 7 KB).

Also:

- UNITY_CLI_BRIDGE_DISABLE / -noUnityCliBridge keeps BridgeBootstrap from
  constructing the host at all, for CI jobs that open the Editor only to
  produce a build. Verified live: no registry entry, no token sidecar, no
  socket. Parsing lives in Runtime/Protocol so it is unit-tested, and a
  source-ordering test pins the check ahead of `new BridgeHost()`.

- Unity Recorder becomes optional, gated on UNITY_CLI_BRIDGE_RECORDER via
  versionDefines. Unity drops a missing asmdef reference silently rather
  than erroring, so the reference stays and every Recorder API touch is
  guarded; `record start` degrades to an install hint while stop/status
  keep serving existing sidecars.

- Declare com.unity.test-framework. The test handlers use TestRunnerApi
  types unguarded and were relying on it arriving transitively through
  Recorder — dropping Recorder surfaced that as CS0246 in a project
  without it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@yhc509
yhc509 merged commit 98e282b into dev Aug 15, 2026
3 checks passed
@yhc509
yhc509 deleted the feat/release-build-hardening branch August 15, 2026 02:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant