Cleaning → AMR — 청소 소유 구동 자원의 안전한 인계
청소가 사용 중인 바퀴를 이동 작업이 가져가려면, 청소 서비스가 먼저 멈추고 자기 점유를 반환해야 한다. 반환 직후 바로 다음 이동을 허용하지 않는다. 별도의 최신 구동부 정지 관측을 확인하고, 그동안 다른 소유자가 끼어들지 않았을 때만 AMR이 새 점유를 얻는다.
이 문서는 승인된 내부 연결 설계와 구현 검증을 다루는 확대도다. 제품 경로 미연결: 기존 DeviceAgent의 청소 명령·MCU 수신 경로를 자동 전환하지 않으며 실제 로봇에서의 정지를 증명하지 않는다. 최신 코드 커밋과 통합 검증 결과는 리팩터링 진행 현황에서 관리한다.
Blueprint 전체 구조 → 도메인별 상태·자원 소유권 → 이 인계 상세 순서로 읽는다.
1. 전체 프레임워크에서의 위치
앱의 Manager는 요청 창구, 도메인의 ManagerService는 실행 상태와 수명의 소유자다. 이 인계는 앱의 Manager나 DeviceAgent 범용 분기문에 넣지 않는다. TaskManager는 실행권을, ResourceManager는 공유 구동 자원의 점유를 관리하고, Cleaning과 AMR은 각각 자기 실행·정지 절차를 책임진다.
skix-framework/base/
core/ 앱이 사용하는 Manager/API 계약
services/core/java/.../server/
control/
lifecycle/ServiceLifecycleSupervisor 서비스 준비 상태·재시작 세대
resource/ResourceManagerService MOVEMENT_BASE 점유·반환·재확인
execution/task/TaskManagerService Task 실행권·취소·완료의 정본
domain/
cleaning/
CleaningManagerService 인계 구성·시작·종료의 소유자
state/CleaningFanStateAuthority 팬 관측 전용 — 전체 정지와 별개
execution/
CleaningTransitionPort 기존 청소 정지 요청·확인 계약
handoff/
CleaningMovementHandoffPort 원본 세대 + 별도 구동부 idle 관측
CleaningMovementHandoffService 청소 점유 하나의 인계 상태·기한
amr/execution/
MovementTaskDispatcher 인계 후 새 AMR 점유·세션 준비
MovementTaskSession 확보한 권한으로 이동을 실행
services/runtime/ 서비스 조립·수명 실행
apps/DeviceAgent/ 제품 명령·수신 어댑터 연결 대상
정본 Java 접두사는 com/sk/airbot/frameworkservice/server/다. 위 폴더는 책임을 보여 주며
새 Binder API나 SystemServer 직접 하드웨어 제어를 추가했다는 뜻이 아니다.
domain/cleaning/execution/은 청소 정지 협력 계약,
domain/cleaning/handoff/는 Cleaning이 소유한 자원의 반환·재확인 수명이다.
공통 TaskManager를 도메인 아래에 배치한 것이 아니다. domain/amr/execution/도
공통 실행권을 사용하는 이동 실행기이며 자체 Task 목록·스케줄러를 만들지 않는다.
2. 왜 기존 prepare만으로는 부족했나
MR6 task_manager의 MovementTaskExecutor는 청소 중단을 요청하고 정지를 기다린 뒤 이동한다.
MR7의 기존 prepare(claim)는 세션을 만들기 전에 구동 자원을 얻는다.
Cleaning이 실제로 MOVEMENT_BASE를 점유하고 있으면 prepare가 먼저 거절되어,
세션 내부의 청소 정지 협력까지 도달할 수 없었다.
새 선택형 prepareAfterCleaning은 그 앞에 원래 소유자의 정지 협력을 연결한다.
기존 prepare API를 삭제하거나 AMR이 Cleaning 토큰을 강제로 해제하도록 바꾸지 않는다.
MR6의 processing=false·상위 stop callback은 제품 구현마다 후처리보다 먼저 바뀔 수 있어
그 값만으로 새로운 물리 안전 증거를 만들지 않는다.
3. 한 단계씩 읽는 자원 인계
| 인계 단계 | 누가 무엇을 하는가 | 구동 자원 상태 | AMR 이동 명령 |
|---|---|---|---|
| REGISTERED | Cleaning이 자기 단일 점유와 원래 공급자를 등록 | HELD — Cleaning 소유 | 금지 |
| STOPPING | 원래 공급자 세대에서 청소 정지를 한 번 요청, 같은 시도의 확인을 기다림 | HELD — Cleaning 소유 | 금지 |
| WAITING_RECONCILIATION | 유효한 청소 정지 확인 뒤 원래 토큰만 반환 | UNVERIFIED — 점유는 끝났지만 재사용 미확인 | 금지 |
| READY | 반환 이후 독립 구동부 idle 관측과 자원 버전을 검사해 재확인 성공 | FREE — 새 점유 시도 가능 | 아직 자동 실행 아님 |
| 새 AMR 세션 | Task·정책·세대를 재검사하고 AMR owner로 새 토큰 획득 | HELD — AMR 소유 | 세션의 추가 조건 검사 후 가능 |
READY는 “그 인계에서 재확인에 성공했다”는 상태다. 영구적인 FREE 보장이 아니며 이후 다른 작업이 점유하면 AMR 획득은 거부된다. READY 핸들을 다시 호출해 자원을 FREE로 바꾸지 않는다. 또한 이 인계의 종료는 기존 청소 Task의 최종 상태를 바꾸는 API가 아니다.
4. 정지라는 말의 네 가지 의미
| 구분 | 근거 | 이 인계에서의 의미 |
|---|---|---|
| 팬 정지 | 팬 수신 패킷의 유효한 RPM 0 | 팬 전용 관측. 청소 전체 종료·구동부 정지로 승격 금지 |
| 청소 전체 종료 | 원래 stop 시도와 세대가 맞는 StopConfirmation |
원래 청소 점유를 반환할 수 있는 협력 절차의 확인 |
| 구동부 정지 | 별도 MovementIdleObservation |
반환 이후 최신 idle 확인. 자원 버전이 일치할 때만 재확인 |
| Task 완료 | 공통 Task의 실행 시도·완료 계약 | 인계 서비스가 대신 성공·취소 완료로 변경하지 않음 |
관측에는 generation, attemptId, sourceSequence, eventId, observedAtMs, idle을 유지한다.
원본 시도·세대, 양수 순번, 공백으로 변형되지 않은 ID, 반환 이후 시각, 미래가 아닌 최신성,
idle=true를 확인한다. 원본 정보가 없는 제품 callback에 현재 Task ID나 현재 시각을 붙여
“새 관측”이라고 합성하지 않는다. 시각 검사는 하드웨어 출처 인증이 아니다.
5. 서비스 수명·동시 접근·실패
CleaningManagerService.configureMovementHandoff는 최초 시작 전에 한 번만 호출하는 내부 구성이다.
같은 lifecycle·ResourceManager와 단조 시계, 양수 대기 기한·관측 유효 시간을 명시해야 한다.
서비스 시작과 종료에 인계 수명이 함께 묶이고 팬 관측 수명은 독립적으로 유지된다.
- 한 항목만 활성화한다. 다른 도메인·여러 자원·이전 세대 토큰과 활성 항목 교체를 거부한다.
advance(handle)는 한 번에 한 단계만 진행한다. 동시에 호출해도 stop 요청·반환·재확인이 중복되지 않는다.- 공급자·시계 callback은 인계 잠금과 Task claim 잠금 밖에서 호출한다. callback 중 종료되면 돌아온 결과를 적용하지 않는다.
- 재확인 토큰은 구동부 관측을 읽기 전에 포착한다. 읽는 동안 자원 버전이 바뀌면 그 관측으로 재확인하지 않는다.
- 관측은 해당 버전을 포착한 뒤 조회를 시작한 시각 이후여야 한다. poll 사이 다른 소유자가 점유·반환한 경우에도 그 이전 idle 캐시를 재사용하지 않는다. 시각의 해상도와 원본 공급자의 신뢰 경계는 남는다.
- 버전 충돌에 사용한 순번·이벤트를 재사용하지 않는다. 다음 시도는 더 큰 원본 순번과 다른 이벤트가 필요하다.
- timeout·공급자 예외·세대 변경·서비스 종료는 후속 명령을 막는다. 원래 점유가 남아 있으면 격리하고, 반환 후 다른 소유자의 토큰은 건드리지 않는다.
- 시간 제한은 advance 호출마다 검사한다. poll을 멈추면 시간만으로 자동 정리되지 않는다. 별도 타이머는 없으며 서비스 종료는 남은 항목을 닫는다.
이 API는 무한 재시도 스케줄러가 아니다. 호출자는 typed 상태·이유를 보고 재호출/종료를 결정한다. 각 준비 호출은 시작과 새 AMR 점유 직전의 Task·정책·서비스 세대를 비교한다. 호출 사이에 dispatcher가 특정 요청을 계속 붙잡지는 않는다. 원래 청소 점유와 공급자 수명은 Cleaning이 관리하므로, 첫 요청이 취소되어도 다음 유효한 요청은 현재 조건을 새로 검사해 인계를 이용할 수 있다. 공급자 세대는 원본 어댑터의 별도 양수 epoch이며 Cleaning 서비스 재시작 횟수와 같을 필요가 없다.
Task 취소·정책 변경은 새 AMR 점유 전에 다시 검사한다. 이미 전달된 청소 정지 명령을 되돌리는 다중 서비스·하드웨어 원자적 트랜잭션은 제공하지 않는다.
6. 검증과 다음 제품 연결
bb001f2 기준 내부 통합 구현·회귀 검증 완료. 명세·품질 리뷰를 통과했고,
정본 소스 격리 후 --rerun-tasks로 서버 636개·SDK 62개, release APK와 경계 검사 4종을 확인했다.
이 중 인계 집중 검증은 32개다. 제품 경로 연결과 실기기 검증은 포함하지 않는다.
내부 테스트는 실제 TaskManager·ResourceManager·CleaningManager·AMR dispatcher를 조립하고 시계와 장치 공급자만 통제한다. 단순 enum 개수나 mock 반환값을 구현 완료 수치로 세지 않는다. 정상 인계뿐 아니라 관측 불일치·만료·재진입·취소·재시작·제3자 점유·재확인 경합을 확인한다. 최종 검증 수치와 코드 커밋은 진행 현황에 기록한다.
제품 활성화 전 남은 일은 다음과 같다.
- 실제 Cleaning 실행이 구동 자원을 점유·등록하는 경로 연결과 직접 명령 우회 감사.
- 청소 정지 확인과 구동부 수신 관측의 원본 시도·세대·순번을 제공하는 제품 어댑터.
- poll 주체·기한 운영 정책·서비스 재시작 시 복구 경로의 제품 조립.
- 부팅·권한·실제 동시 요청·물리 정지와 이동의 기기 검증.
원본 공급자가 요구 근거를 제공할 수 없으면 기본 제품 경로를 켜지 않는다. 전체 Cleaning 상태 머신이나 범용 선점 스케줄러가 완성되었다고 표시하지 않는다.