← Docs hub

SKIX Blueprint 기준 MR7 리팩터링 정합성 감사 및 교정안

이 문서는 초기 기준의 감사 기록이다. 현재 팀 단위 Framework의 폴더·모듈·업무 경계는 2026-09-22 두 브랜치 비교를 참고한다.

결론부터: 무엇이 맞고 무엇을 바로잡아야 하는가

Blueprint가 목표 기준선이다. 분석 대상은 packages-mr7의 refactor/clean-architecture-prebuilt 브랜치, HEAD 5d0ee58이다.

MR7은 typed SDK, 공통 Binder 연결, 명령별 단일 domain owner, handler 분리까지는 Blueprint와 같은 방향이다. 그러나 이것은 목표 아키텍처의 Product Interface Layer와 Domain Framework Plane 일부를 만든 것이지, Framework Control Plane이나 Managed Execution Plane을 구현한 것이 아니다. 특히 기존 StateManager, CmdPolicyManager, EventManager를 이름이 비슷하다는 이유로 각각 StateMirror, Policy Engine, Event and Evidence Fabric으로 간주하면 구현 방향이 틀어진다.

핵심 교정 문장: 이름이 비슷하다고 같은 책임이 아니다. 현재 리팩터링은 호출 외형과 도메인 분리를 잘 시작했지만, 상태·정책·자원·Task·완료 근거의 권위 원본은 아직 분리하지 않았다.

<a id="blueprint-work-area"></a>

Blueprint 전체에서 MR7이 작업된 영역

MR7 = Product Interface + Domain Framework 기반 구현
Framework Control Plane + Managed Execution Plane 미구현

아래 그림은 별도의 유사 구조도를 새로 그린 것이 아니다. Blueprint의 원본 도형을 단일 SVG 안에 그대로 포함하고, MR7 판정만 그 위에 얹었다. 대칭은 역할과 경계가 직접 대응함, 유사는 일부 대응, 다름은 이름·호출 형태보다 책임이 다름, 미구현은 목표 owner가 없음을 뜻한다.

Blueprint 원본 위 MR7 대칭·유사·다름·미구현 오버레이

주 구조도. Blueprint 원본 기반 MR7 작업 위치
02A Manager와 05 Domain Execution은 대칭되는 기반이다. 03은 유사하지만 Bundle 계약이고, 04 중앙 Product Framework Service는 다르거나 미구현이다. 빨간 점선이 현재의 중앙 authority 우회를 표시한다. 외부 SVG를 다시 불러오지 않는 독립형 파일이므로 위키 <img> 안에서도 원본과 판정이 함께 표시된다.
독립형 오버레이 SVG 열기

Blueprint 영역 MR7 현재 위치 이번 작업의 의미
Experience and Consumer Layer SKMLauncher2, AirClearWorkFragment, AirClearViewModel 새 Product API의 사용처. MVVM 분석은 Experience/Consumer의 앱 내부 사용 사례
Product Interface Layer SkixManager, BaseManager, typed managers 주 작업 ①: 문자열·Bundle 호출을 typed domain API로 감쌈
Framework Control Plane 목표 StateMirror, Policy Engine, Resource Arbiter, CapabilityRegistry 없음 미구현: 기존 유사 이름 클래스를 목표 authority로 간주하면 안 됨
Managed Execution Plane 정식 Task lifecycle, Workflow, Evidence, TaskState 없음 미구현: isDelivered()와 물리 완료를 분리해야 함
Domain Framework Plane ModuleCommandDispatcher, domain handlers 주 작업 ②: 명령별 domain owner와 handler 분리
Device Integration Plane 기존 DeviceAgent·AMR/vendor 호출·callback 기존 실행 경로 재사용, 이번 작업의 주 재설계 영역은 아님

현재는 Product Interface → IDeviceControl.sendModuleCommand(Bundle) → MainApi → ModuleCommandDispatcher → domain handler로 내려간다. 즉 중앙 제어·관리형 실행 계층을 건너뛰는 현재 경로다. 이 브랜치는 Blueprint를 완성한 것이 아니라, 향후 Control Plane과 Managed Execution Plane을 사이에 삽입할 수 있도록 위쪽 typed 호출 창구와 아래쪽 domain executor 경계를 만든 단계다.

목표 구조의 정의와 각 계층 책임은 원래 Blueprint의 현재 MR7 위치 설명을 먼저 보고, 이 문서에서는 해당 판정의 코드 근거와 교정 순서를 확인하면 된다.

앱 사용 사례: MVVM 기준 1:1 대칭 분석

아래 그림은 전체 리팩터링 범위를 뜻하지 않는다. Experience and Consumer Layer의 SKMLauncher2가 Product Interface를 사용하는 방식을 확대해서 보는 앱 내부 상세도다. 기준 문서의 MVVM과 단방향 상태 흐름에 있는 원본 SVG와 원본 도형을 단일 SVG 안에 그대로 포함했다. 새 구조를 같은 좌표로 다시 그린 것이 아니라, 원본의 세 섹션과 11개 슬롯 위에 MR7 AirClear 대응 외곽선과 배지만 얹었으므로 같은 박스에서 차이를 바로 읽으면 된다.

MVVM UDF 원본 위에 MR7 AirClear 대칭·유사·다름·미구현을 표시한 오버레이

그림 2. MVVM·UDF 원본 기반 MR7 1:1 대응
초록 대칭, 주황 유사, 빨강 다름, 회색 점선 미구현이다. 아래쪽 빨간 설명은 stopAirClear()가 transport ACK를 UI 완료로 승격하는 책임 차이를 표시한다. 외부 SVG를 다시 불러오지 않는 독립형 파일이므로 위키 <img> 안에서도 원본과 판정이 함께 표시된다.
독립형 오버레이 SVG 열기

원본 MVVM 슬롯 MR7 실제 대응 정합성 판정 구현자가 바꿔야 할 방향
View AirClearWorkFragment 부분 정렬: uiState, uiEvent 관찰 버튼의 ViewModel 직접 호출을 UiAction 입력으로 통일 — 현재는 UiAction 미도입
FeatureViewModel AirClearViewModel 의미 교정: ViewModel은 있으나 mutable AirClearUiState, Reducer 없음 불변 FeatureUiState와 일회성 UiEffect로 분리
UseCase · Repository UseCase 없음 · AirCleanerRepository 부분 정렬: typed manager 호출은 맞음 command 반환과 Flow<TaskState> 기반 완료 관찰 분리
SkixUiManager SkixAirCleanerManager 잘못 매칭하면 안 됨: SkixUiManager 미구현 domain command facade는 유지하고 UI session facade를 별도 도입
Binder · AIDL IDeviceControl.sendModuleCommand(Bundle) 전환 adapter 새 공개 계약은 typed/versioned request로 제한
SkixUiService · UiSessionController 대응 없음 SkixUiService 미구현 session lifecycle, foreground, restore 권위 신설
TaskSessionBinder 대응 없음 TaskSessionBinder 미구현 taskId, observe, cancel, terminal 결과 계약 신설
Android · Device Domain DeviceAgent → Dispatcher → handler → vendor callback 부분 정렬 callback을 공통 evidence stream으로 정규화
FeatureUiState AirClearUiState 의미 교정: setter가 같은 객체를 변경 immutable snapshot으로 교체
UiSessionState 대응 없음 UiSessionState 미구현 화면 session 수명의 권위 원본 신설
TaskState 대응 없음 TaskState 미구현 실행 evidence 기반 terminal 상태 신설

현재 STOP 흐름은 btnAirClearStop → AirClearViewModel.stopAirClear() → AirCleanerRepository.stopAirClear() → SkixResult.isDelivered() → fetchAirCleanerState() → AIR_CLEAR_STOP이다. 여기서 isDelivered()는 Binder 전달 성공인데, 곧바로 화면의 완료성 이벤트를 발행하므로 transport ACK를 UI 완료로 승격한다. 목표 구조에서는 ACCEPTED와 물리 동작의 SUCCEEDED/FAILED를 TaskState로 분리해야 한다. 이 판정은 정적 코드 근거이며 실제 청소 종료 완료는 실기기 미검증이다.

Blueprint 6개 계층에 MR7 현재 구현을 겹쳐 본 정합성 지도

보조 그림. Blueprint 목표 위의 MR7 구현 정합성
초록은 유지할 기반, 노랑은 전환 중인 기반, 빨강은 의미를 다시 분리해야 하는 부분, 회색은 아직 없는 부분이다. 원본 SVG 열기

보조 구조도: 제품 Framework 계층과 Runtime 상세

위 MVVM 1:1 대칭도가 UI 구조 판정의 기준이다. 아래 그림들은 UI 비교를 대체하지 않으며, Blueprint의 전체 구조, AOSP 위에서의 위치, Android Manager / Service 분리 관점에서 하위 runtime과 제품 Framework 경계를 더 자세히 보여 주는 보조 자료다.

Blueprint 전체 구조와 같은 좌표에 배치한 MR7 구현

그림 A. 전체 구조 matched view
Product Interface와 Domain Framework에는 유지할 구현이 있지만, 그 사이의 Control/Managed Execution authority는 비어 있거나 기존 대형 클래스에 섞여 있다. 원본 SVG 열기

Blueprint AOSP 배치와 같은 좌표에 배치한 MR7

그림 B. AOSP position matched view
MR7 DeviceAgent는 system_server의 SystemService가 아니라 /system/priv-app의 platform-signed, persistent 제품 Runtime이다. 논리 Service를 나누되 초기 단계부터 APK·프로세스를 쪼개지 않는다. 원본 SVG 열기

Blueprint Manager Service 분리와 같은 좌표에 배치한 MR7

그림 C. Manager / Service contract matched view
SkixManager와 typed domain manager는 호출 창구로 유지한다. 상태·정책·자원·Task·완료의 authority는 DeviceAgent 프로세스 안의 논리 Service로 새로 분리해야 한다. 원본 SVG 열기

실제 요청과 callback을 끝까지 따라간 결과

MR7 실제 요청 callback 경로와 Blueprint evidence loop

그림 D. Runtime trace
typed 호출이 legacy Binder로 들어가고 callback이 상태·UI·IoT side effect로 퍼지는 실제 경로다. 원본 SVG 열기

추적 지점 MR7 정적 증거 Blueprint 판정 교정
SDK 진입 SkixManager → typed manager → BaseManager 부분 정렬 Product API seed로 유지
Binder ingress IDeviceControl.sendModuleCommand(Bundle) 전환 adapter 신규 공개 계약은 typed/versioned request로 제한
호출자 신뢰 Binder.getCallingPid()는 death monitor에 쓰고, routing 이름은 전달받은 classname 사용 방향 수정 필요 UID·package·certificate를 Binder에서 파생하고 capability allowlist 적용
callback 해제 unregisterCallback() 본문이 주석 처리되고 항상 0 반환, 즉 no-op P0 결함 후보 callback/name/death recipient를 원자적으로 해제하고 leak 계측
선행 gate MainApi가 special mode와 StateManager.checkBlockedStatus를 직접 분기 정책 계약 미분리 side-effect-free PolicyDecision을 shadow로 먼저 도입
도메인 routing 31 registered handlers, 검증 결과 272 methods / 272 unique owners 정렬됨 dispatcher를 executor adapter 경계로 유지
호출 반환 DeviceControlService가 Binder 반환 직후 SkixResult.delivered(output) 생성 transport ACK ACCEPTED로만 해석하고 SUCCEEDED는 evidence 대기
callback 처리 MainService가 decode·state·UI·IoT·제품 action을 한 흐름에서 수행 책임 혼재 Connector → Decoder → State Writer/Evidence Adapter → Subscriber 분리

classname은 callback routing metadata일 수는 있지만 보안 identity가 아니다. Proxy에서 stack trace나 호출자 입력으로 만들어 서비스에 넘기는 문자열을 권한 판단에 사용하면 안 된다. 또한 unregisterCallback()의 no-op은 등록 수명과 해제 수명이 비대칭임을 뜻한다. 이 두 항목은 공개 Manager 확대보다 먼저 닫아야 한다.

이름 변경이 아니라 책임 추출

현재 대형 클래스에서 Blueprint 책임을 추출하는 지도

그림 E. Responsibility extraction
StateManager, CmdPolicyManager, EventManager, MainService를 목표 이름으로 rename하지 않고 observe → shadow → route → own 순서로 책임을 추출한다. 원본 SVG 열기

새로 확인된 TaskExecutor 의미 충돌

MR7 TaskExecutor와 Blueprint TaskManager Core의 의미 차이

그림 F. TaskExecutor semantic gap
현재 구현은 유용한 직렬 queue seed지만 Task lifecycle authority가 아니며, 공유 숫자 ID 때문에 도메인 간 간섭 위험이 있다. 원본 SVG 열기

TaskExecutor는 단일 HandlerThread에 ITask.execute(): void를 넣고 Message.what 숫자로 대기·실행 여부와 삭제를 관리한다. 그런데 WSS_COMMAND_ID_BASE = 2000과 STREAMING_COMMAND_ID_BASE = 2000이 동일하다. 따라서 예를 들어 WSS START와 Streaming START는 모두 2001이며, hasMessages(2001) 또는 removeMessages(2001)가 상대 도메인의 작업을 대기 중으로 오판하거나 함께 지우는 교차 취소 가능성이 있다. 이는 정적 코드에서 확인되는 구조 위험이며 실제 재현 여부는 동시 요청 실기기 테스트가 필요하다.

더 중요한 차이는 Task ID가 업무 식별자가 아니라 command type 숫자라는 점이다. request source, idempotency, timeout, cancellation reason, checkpoint, EvidenceRecord, terminal TaskSnapshot이 없다. 따라서 이 클래스를 TaskManager Core로 rename하지 말고, 우선 domain namespace를 분리한 뒤 기존 queue를 WSS/Streaming executor 내부 구현으로 한정한다.

버리지 말고 공통 계약으로 승격할 vertical slice

MR7의 재사용 가능한 구현 seed와 Blueprint 승격 조건

그림 G. Reusable vertical slices
현재 구현에서 이미 목표 성질을 가진 작은 단위를 골라 공통 계약으로 승격한다. 원본 SVG 열기

현재 seed 같은 성질 승격할 때 반드시 추가할 것
DeviceStateSnapshot immutable state, source, observed time, stale 판정 domain aggregate, sequence, freshness policy, read-only subscription
CameraAccessPolicy client lease, reference count, exclusive/shared 판단 trusted caller, resource descriptor, TTL, fence, release evidence
KVS session 계약 sessionId, fence, lease/command expiry, correlationId, replyTo, heartbeat/result common task/evidence schema와 sequence; liveview의 session authority는 유지
Dispatcher owner registry command별 단일 owner version, availability, constraints를 갖춘 CapabilityRegistry projection

이 네 seed는 Blueprint 전체가 구현됐다는 증거가 아니다. 각각 상태·자원·evidence·capability의 한 도메인 vertical slice일 뿐이다. 하지만 전면 재작성 대신 이 계약들을 일반화하면 기존 실행 owner를 보존하면서 목표 구조로 이동할 수 있다.

구현·릴리스 Gate

Blueprint 수렴을 위한 P0 P1 P2 P3 릴리스 게이트

그림 H. Release gates
안전 경계부터 닫고 관찰·shadow를 거친 뒤 한 기능의 authority만 옮긴다. 원본 SVG 열기

단계 구현 범위 다음 단계 진입 기준
P0 Binder 인증, callback 정상 해제, TaskExecutor ID namespace 분리 미승인 caller 거부, callback 잔존 0, WSS/Streaming 교차 취소 0
P1 read-only StateMirror, pure policy shadow, callback evidence adapter 기존/신규 판정 diff 수렴, 기존 executor side effect 정확히 1회
P2 한 기능의 Capability + ResourceLease + Task lifecycle ACCEPTED와 SUCCEEDED 분리, timeout/cancel terminal 1회, evidence 기반 성공
P3 Schedule/UI/IoT subscriber와 domain별 authority 순차 전환 reboot/rebind/callback-loss 복구 및 이동·도킹·청정 실기기 Gate 통과

추천 첫 slice는 Camera 또는 Docking이다. Camera는 기존 lease seed가 있고, Docking은 Binder 접수와 물리 도착 완료를 분리하기 쉬워 Task/evidence 계약의 수용 기준이 명확하다.

구현자에게 먼저 전달할 교정 지시

우선순위 지시 이유
즉시 중단 StateManager를 이름만 바꿔 StateMirror로 선언하는 작업 현재 클래스는 상태 저장뿐 아니라 차단 검사와 LCD·SoundFlow·Vision·청정 제어까지 수행한다.
즉시 중단 CmdPolicyManager를 그대로 공통 Policy Engine으로 승격 정책 판정과 stopAllAction, pause/resume, returnToStation 물리 실행이 결합돼 있다. 정책이 실행을 직접 소유하면 안 된다.
즉시 중단 ModuleCommandDispatcher 또는 domain handler를 TaskManager로 부르기 현재 dispatcher는 문자열 명령의 owner를 고를 뿐, Task ID·대기열·취소·시간 제한·완료 근거를 소유하지 않는다.
즉시 중단 typed manager 수를 늘리는 것만으로 Framework 완성도를 판단 도메인별 편의 API 증가는 Control Plane의 상태·정책·자원·기능 명세 부재를 해결하지 않는다.
즉시 유지 SkixManager의 단일 연결, BaseManager의 legacy 격리, typed request/result 모델 Product Interface Layer의 올바른 전환 기반이다.
즉시 유지 ModuleCommandDispatcher와 명령별 단일 handler owner Domain Framework Plane의 실행 변환 경계로 재사용할 수 있다.
즉시 착수 기존 owner를 읽는 read-only StateMirror projection 새 상태 원본을 하나 더 만들지 않고 출처·관측 시각·최신성을 표준화한다.
즉시 착수 CmdPolicyManager에서 순수 판정과 실행 side effect 분리 shadow decision 비교 후 기능별로 실행 owner를 옮길 수 있게 한다.
즉시 착수 callback을 EvidenceRecord로 변환하는 adapter와 correlation ID Binder 응답과 실제 도착·도킹·청정 종료를 구분한다.
즉시 착수 Runtime Binder 공통 authorization gate exported privileged service를 signature permission, UID·package·certificate, capability로 보호한다.

판정 기준과 증거 경계

판정 의미
정렬됨 Blueprint의 책임 경계와 MR7 구현 책임이 실질적으로 일치하며 다음 계층의 기반으로 유지 가능
부분 정렬 같은 방향의 구조가 있으나 계약·권위 원본·범위가 목표보다 좁음
미구현 대응하는 권위 원본이나 lifecycle 계약이 현재 브랜치에 없음
방향 수정 필요 이름이나 외형은 유사하지만 실제 책임 결합이 Blueprint 원칙과 충돌

이 문서는 소스, Git, Manifest와 로컬 정적 구조를 근거로 한다. AOSP 통합, OTA, 동일 서명 APK 교체, 실제 Binder 호출자 권한, 로봇의 이동·도킹·청정 물리 완료는 실기기 미검증이다.

6개 계층 종합 판정

Blueprint 계층 MR7 대응 구현 판정 유지할 성질 반드시 보완할 것
Experience and Consumer Layer SKMLauncher2·PUI·IoT 등 호출 앱의 SDK 채택 부분 정렬 앱이 raw proxy 대신 typed API로 이동 앱 내부 UDF/MVVM, UI session·Task 관찰 계약은 별도 검증 필요
Product Interface Layer SkixManager, SkixDeviceManagers, typed managers/models, DeviceConnectionService 부분 정렬 단일 연결과 typed facade, legacy adapter 격리 State·Capability·Policy·Task·Health의 횡단 Manager/Service 계약 부재
Framework Control Plane StateManager, CmdPolicyManager, EventManager, camera access policy 방향 수정 필요 기존 안전 규칙과 도메인 상태는 회귀 기준선 StateMirror·순수 Policy Engine·Resource Arbiter·CapabilityRegistry·Health 분리
Managed Execution Plane schedule handler와 기존 직접 실행, 별도 donor 후보 미구현 예약 저장·도메인 실행 경험 Task lifecycle, workflow, queue, timeout, cancellation, evidence authority
Domain Framework Plane ModuleCommandDispatcher, 31개 handler, 272개 단일 command owner 정렬됨 기존 장치 동작을 typed 요청과 연결하는 adapter 경계 handler 내부의 횡단 정책·상태·완료 판단을 Control/Execution Plane으로 이동
Device Integration Plane platform-signed DeviceAgent, AMR·IoT·vendor/HAL 연결, MainService callback 부분 정렬 실제 하드웨어·연동 Agent 연결의 기존 owner 유지 callback decode·상태 변경·UI·IoT 전달·evidence 방출 책임 분리, 공통 Binder 인증

1. Experience and Consumer Layer

Blueprint 목표

시스템 앱·PUI·IoT·승인된 파트너가 제품 기능을 직접 Binder 문자열로 조합하지 않고 Repository/UseCase를 거쳐 typed Manager를 사용한다. 앱 화면 상태는 앱이 소유하고, 제품 실행 상태는 Runtime Service와 TaskManager가 소유한다.

MR7의 같은 방향

차이와 수정 방향

MR7 소스만으로 모든 consumer가 UiAction → ViewModel → Repository → Manager를 따르고 있는지, 화면과 기기 Task의 lifecycle을 분리했는지는 증명되지 않는다. 따라서 “앱 API 교체 완료”를 “Experience Layer 완료”로 쓰면 안 된다. 소비 앱별로 direct proxy/Binder/Bundle 호출 잔존을 검사하고, 장기 동작은 callback을 곧바로 화면 완료로 해석하지 말고 Task snapshot으로 투영해야 한다.

2. Product Interface Layer

Blueprint 목표

Manager는 호출 편의·연결 대리이고, Service는 상태·정책·실행 lifecycle의 최종 책임자다. 첫 배치는 각 기능을 별도 APK로 쪼개는 것이 아니라 DeviceAgent 프로세스의 하나의 Runtime Binder 진입점 뒤에 논리 모듈로 둔다. 신규 공개 계약은 버전이 붙은 typed request/result/event를 사용한다.

MR7의 같은 방향: 유지해야 할 기반

MR7 코드 확인된 책임 Blueprint와 같은 성질 판정
SkixManager 한 앱 프로세스의 단일 facade, 연결·환경·업데이트·도메인 manager 제공 SkixFramework Client Core의 출발점 부분 정렬
DeviceConnectionService legacy adapter 한 개의 연결·해제·연결 상태·event 전달 Manager별 bind 중복 방지 부분 정렬
BaseManager typed method를 legacy sendModuleCommand로 변환 Branch by Abstraction의 호환 adapter 정렬됨
DeviceStateSnapshot source, observed time, stale 판정 포함 StateMirror 공개 snapshot의 계약 씨앗 부분 정렬
typed domain managers 앱에서 명령 문자열과 Bundle 형식을 숨김 명확한 Product API로 이동 부분 정렬

아직 목표가 아닌 부분

BaseManager의 주석과 구현은 typed call이 최종적으로 legacy Bundle과 sendModuleCommand(indata, outdata)로 변환됨을 명시한다. 이것은 올바른 전환 경계지만 새로운 Runtime Service 계약 자체는 아니다. 또한 MR7에는 다음 Blueprint 횡단 API가 없다.

현재 SkixEventManager는 이름과 달리 screen/sub-state와 EyeLED scene 명령을 보내는 도메인 manager다. 이를 Blueprint의 SkixExecutionEventManager로 확장하지 말고, SkixUiManager 또는 UI domain adapter로 명확히 이름과 위치를 정리해야 한다.

3. Framework Control Plane

현재 이름과 Blueprint 책임 사이의 의미 차이

그림 2. 이름 유사성 때문에 생기는 가장 큰 오해
왼쪽의 기존 class를 오른쪽 목표 모듈로 단순 rename하지 않고, 읽기 projection·순수 판정·evidence adapter로 분리한다. 원본 SVG 열기

3.1 StateManager는 아직 StateMirror가 아니다

StateManager는 707줄 enum singleton이다. main/sub state, wizard·mapping·ICT 등 제품 상태를 보관하는 동시에 checkBlockedStatus로 문자열 method를 차단하고, 상태 전환 과정에서 LCD, SoundFlow, Vision, 청정과 CmdPolicyManager pause/resume까지 호출한다.

Blueprint의 StateMirror는 기존 owner를 대체해 명령을 실행하는 객체가 아니라, 여러 도메인의 권위 상태를 출처·관측 시각·최신성과 함께 읽어 주는 공통 최신본이다. 첫 단계는 기존 write owner를 유지하고 read-only projection을 붙이는 것이다.

3.2 CmdPolicyManager는 아직 순수 Policy Engine이 아니다

CmdPolicyManager는 1,581줄이며 조건 판정뿐 아니라 stopAllAction, 이동 pause/resume, AMRMotor.returnToStation, InterScheduleManager 제어를 직접 수행한다. 이 상태로 공통 Policy Engine이 되면 정책을 조회하는 순간 장치가 실행되거나, TaskManager와 이중 실행 owner가 생길 수 있다.

교정 순서는 다음과 같다.

  1. 기존 method별 입력 상태와 allow/deny/reason을 반환하는 side-effect-free evaluator를 추출한다.
  2. 기존 경로가 한 번만 실행하는 동안 새 evaluator는 shadow decision만 기록한다.
  3. 차이를 검수한 기능만 PolicyDecision → ResourceLease → Domain Executor 순으로 연결한다.
  4. 최종 실행은 handler/adapter 한 곳만 소유하고 Policy Engine에는 장치 제어 호출을 두지 않는다.

3.3 EventManager는 아직 Event and Evidence Fabric이 아니다

현재 EventManager 414줄은 main/sub state와 EyeLED scene을 중심으로 제품 표시 상태를 조정한다. 요청 ID, Task ID, sequence, event type, physical completion evidence를 공통 계약으로 연결하지 않는다. 따라서 기존 이름을 유지한 채 범용 event bus 역할을 추가하지 말고 UI scene 책임과 실행 evidence를 분리해야 한다.

3.4 부분적으로 재사용할 수 있는 구조

카메라의 CameraAccessPolicy는 client별 lease와 reference count, exclusive/shared 상태를 관리한다. 이것은 Resource Arbiter와 비슷한 성질을 가진 좋은 vertical slice다. 다만 카메라 전용 in-memory policy이므로 이동·화면·오디오까지 포괄하는 공통 ResourceLease 권위 원본이라고 부를 수 없다. 카메라 동작을 그대로 일반화하기보다 resource descriptor, owner, mode, TTL/fence, release evidence를 공통 계약으로 추출하고 카메라 adapter가 이를 사용하게 한다.

4. Managed Execution Plane

현재 판정: 미구현

현재 브랜치에는 Blueprint가 요구하는 TaskManager Core, workflow, queue, timeout, cancellation, checkpoint, TaskSnapshot, 완료 근거 기반 최종 상태의 권위 원본이 없다.

SkixScheduleManager가 typed schedule 요청을 만들고 ScheduleCommandHandler가 예약 동작을 처리하는 것은 Schedule API의 일부로는 맞다. 그러나 handler가 CmdPolicyManager.stopAllAction, InterScheduleManager.start/pause/resume, returnToStation을 직접 호출하므로 예약 시작이 곧 managed task 제출은 아니다.

다음과 같이 고쳐야 한다.

Schedule trigger
  → TaskSubmission(scheduleId, capabilityId, inputs)
  → PolicyDecision
  → ResourceLease
  → Domain Executor Adapter
  → EvidenceRecord
  → TaskSnapshot(SUCCEEDED | FAILED | CANCELLED | TIMED_OUT)

TaskManager는 handler를 대체해 장치 코드를 다시 구현하지 않는다. 기존 handler 또는 더 작은 executor를 호출하고 lifecycle만 소유한다. Binder transport ACK는 ACCEPTED일 뿐 SUCCEEDED가 아니다.

5. Domain Framework Plane

가장 강하게 정렬된 부분

MainApi는 ModuleCommandDispatcher에 alert, air quality, camera, cleaning, manage, provisioning, setting, system, map, OTA, interaction, LLM, movement, schedule, test 등을 포함한 31개 handler를 등록한다. 검증 스크립트 기준 272개 method가 272개 unique owner에 연결된다. 이것은 거대한 switch에서 도메인별 executor adapter로 나누려는 Blueprint 방향과 정확히 맞는다.

MR7의 실제 요청 경로와 Blueprint 대응 위치

그림 3. typed 외형부터 기존 실행까지의 실제 연결
Product Interface와 Domain Framework는 형성됐지만 그 사이 Control/Execution Plane이 아직 비어 있음을 보여준다. 원본 SVG 열기

이 구조를 잘못 확장하지 않는 규칙

6. Device Integration Plane

현재 위치

DeviceAgent는 Android.mk에서 $(PRODUCT_OUT)/system/priv-app, LOCAL_CERTIFICATE := platform으로 배치된다. Android system_server의 SystemService가 아니라 플랫폼 서명 privileged app 내부의 제품 Runtime이다. 이 배치는 Blueprint의 초기 “하나의 Runtime Binder 진입점 뒤 논리 모듈”과 양립한다. 논리 책임을 나누기 위해 곧바로 APK나 프로세스를 여러 개 만들 필요는 없다.

MainService의 집중 책임

MainService 640줄의 AMR callback은 callback Bundle 해석, StateManager 조회·변경, ICT 분기, IoT callback 전달, PUI/표시 반응, 오류와 product action을 한 흐름에서 처리한다. Device Integration Plane의 connector가 Control Plane의 상태와 Experience Layer의 반응까지 소유하는 형태다.

다음 네 경계로 나눈다.

  1. Connector: AMR/IoT service bind와 연결 lifecycle만 소유
  2. Callback Decoder: legacy Bundle을 typed domain event로 변환
  3. State Writer / Evidence Adapter: 기존 state owner 갱신과 물리 완료 근거 발행
  4. Subscriber: IoT, UI, Task가 권한과 관심 이벤트에 따라 소비

또한 .DeviceAgent가 exported인 반면 전체 Runtime service에 일관된 signature permission 관문이 확인되지 않는다. 공개 Manager를 확장하기 전에 Binder.getCallingUid() 기반 UID·package·certificate 검증과 method/capability allowlist를 진입점 한 곳에서 적용해야 한다. payload의 clientName/source는 인증 근거가 아니다.

현재 경로를 목표 경로로 고치는 한 장의 설계

MR7 현재 구조에서 Blueprint 목표로 이동하는 교정 방향

그림 4. 유지·분리·추가·금지 경계
기존 executor는 유지하고, 그 앞에 상태·정책·자원·Task 책임을 순서대로 삽입한다. 원본 SVG 열기

구분 현재 교정 목표 금지할 지름길
호출 API typed manager → legacy adapter 횡단 manager + typed domain API manager를 God facade로 확대
상태 mutable singleton + side effect read-only StateMirror + 기존 단일 writer 복제 상태 DB를 새 권위 원본으로 생성
정책 판정과 실행 결합 pure PolicyDecision + executor 분리 canExecute()가 모터·화면을 제어
자원 도메인별 busy/lease 공통 Resource Arbiter boolean busy만으로 선점·복구 처리
실행 handler의 즉시 호출 Task lifecycle이 domain executor를 호출 TaskManager가 장치 구현을 복제
완료 callback별 임의 해석 correlation ID가 있는 EvidenceRecord Binder return을 물리 완료로 판정
보안 부분별 개별 검사 Runtime Binder 공통 gate clientName/source 문자열 신뢰

구현 순서: 무엇을 언제 옮길 것인가

Blueprint 기준 MR7 단계별 이행 순서

그림 5. 한 번에 갈아엎지 않는 Blueprint 수렴 순서
각 단계는 기존 물리 실행 owner를 하나로 유지하고, 검증된 기능만 다음 단계로 넘긴다. 원본 SVG 열기

단계 구현 통과 조건 rollback
0 272 command의 caller·입력·차단·callback·물리 완료 기준 동결 command ownership verifier + 대표 회귀 기준선 변경 없음
1 DeviceStateSnapshot을 확장한 read-only StateMirror adapter source·timestamp·freshness와 기존 state 값 동등 projection 비활성화
2 callback decoder와 Event/Evidence 이중 기록 누락·중복·순서·correlation 검증 신규 event 발행 중단
3 CmdPolicyManager 규칙의 pure evaluator + shadow decision allow/deny/reason 차이 승인 새 판정 무시
4 CapabilityRegistry에 입력·정책·자원·executor·evidence 연결 대표 capability descriptor 계약 시험 registry 조회 비활성화
5 camera부터 공통 Resource Arbiter vertical slice exclusive/shared/timeout/release/fence 시험 기존 camera policy 복귀
6 이동 또는 복귀 한 기능을 TaskManager Core로 전환 중복 물리 실행 0, 취소·timeout·실제 완료 확인 기능 flag로 직접 handler 복귀
7 schedule이 direct action 대신 Workflow/Task 제출 reboot 복구·중복 방지·예약 완료 evidence 기존 schedule 실행 경로 복귀
8 UI session·추가 도메인 확장 실기기 Gate, 성능·장기·권한·rollback drill 기능별 owner switch 복귀

Blueprint 핵심 구성요소별 최종 점검표

목표 구성요소 MR7의 씨앗 현재 판정 다음 코드 단위
SkixFramework Client Core SkixManager, DeviceConnectionService 부분 정렬 version/capability/health와 typed event 연결
StateMirror DeviceStateSnapshot, 기존 StateManager 값 부분 정렬 read-only projection; writer와 side effect 유지 분리
Policy Engine CmdPolicyManager 규칙 방향 수정 필요 pure evaluator와 reason code 추출
Resource Arbiter CameraAccessPolicy 부분 정렬 공통 resource descriptor/lease/fence 계약
CapabilityRegistry domain manager + handler owner 목록 미구현 typed input부터 evidence까지 descriptor로 연결
Lifecycle Supervisor connection auto-rebind 일부 부분 정렬 component READY/DEGRADED/RECOVERING/FAILED 모델
TaskManager Core schedule/direct action, 별도 donor 후보 미구현 task state authority와 한 vertical slice
Evidence Adapter AMR/IoT callback 미구현 transport ACK와 physical completion 분리
Event and Evidence Fabric ModuleCallbackRouter 부분 정렬 correlation, sequence, access scope, bounded replay
Domain Framework Plane dispatcher + domain handlers 정렬됨 executor adapter로 유지하고 횡단 책임 제거

구현 리뷰에서 바로 사용할 질문

다음 질문에 “예”라고 답할 수 없으면 Blueprint에 수렴한 구현이 아니다.

  1. 이 클래스는 Manager인가 Service인가, 최종 상태 owner는 어디인가?
  2. 상태 snapshot에 source, observed time, freshness가 있는가?
  3. 정책 판정 함수가 장치 실행 없이 같은 입력에 같은 결정을 반환하는가?
  4. 충돌 자원에 명시적인 owner, lease, release/expiry가 있는가?
  5. 장기 동작에 Task ID, 상태 전이, 취소, timeout이 있는가?
  6. ACCEPTED와 물리 완료 SUCCEEDED를 다른 evidence로 판정하는가?
  7. command router와 Task scheduler의 책임을 섞지 않았는가?
  8. 같은 물리 행위를 실행하는 owner가 전환 중에도 정확히 하나인가?
  9. exported Binder 진입점이 UID·package·certificate·capability를 공통 검사하는가?
  10. 기능 flag로 새 판단 또는 실행 owner만 안전하게 되돌릴 수 있는가?

부록: 기존 TaskManager 분석의 올바른 위치

별도 TaskManager 작업본의 lifecycle, workflow, scheduler, completion test는 Managed Execution Plane을 구현할 때 참고할 donor다. 그러나 MR7 전체와 직접 병합하거나 Blueprint 전체의 중심으로 삼지 않는다. MR7의 올바른 기준선은 현재 domain owner와 제품 동작이며, donor에서는 다음 책임만 선택 이식한다.

직접 Git 병합, 일괄 패키지 이식, handler 내부 TaskManager 복제는 선택하지 않는다. 이 부록의 목적은 Blueprint의 Managed Execution Plane을 채우는 것이며 문서의 목표 구조를 바꾸는 것이 아니다.

관련 문서

Keyboard shortcuts

⌘K / Ctrl+KOpen command palette
/Focus search
g hGo to home
g pGo to projects
g sGo to sessions
j / kNext / prev row (tables)
?Show this help
EscClose dialogs

Structured queries

Mix key:value filters with free text in the palette:

type:sessionOnly session pages
project:llm-wikiFilter by project name (substring)
model:claudeFilter by model name (substring)
date:>2026-03-01Sessions after a date
date:<2026-04-01Sessions before a date
tags:rustPages mentioning a tag/topic
sort:dateSort results by date (newest first)

Example: type:session project:llm-wiki date:>2026-04 sort:date