이 페이지는 분할 전 전체 사양을 한 파일에서 확인하기 위한 보존본이다. 일반 탐색은 TaskManager 사양 허브를 사용한다.
DeviceAgent TaskManager 기준 사양서 · 전체 원문 보존본
DeviceAgent TaskManager가 여러 요청 경로의 기기 동작을 Task와 Workflow라는 공통 실행 단위로 관리하기 위한 기준을 정의한다. 적용 범위는 책임 경계, 공개 API, 실행 정책, 상태 생명주기, 완료 판정, 예약 실행, 외부 연동, 호환성과 인수 기준이다.
TaskManager는 요청의 의미를 해석하는 계층이 아니다. 제출된 실행 의도를 순서, 상태, 자원, 취소, 완료와 실패 계약에 따라 제어하고, 실제 기기 동작 결과를 구조화된 상태와 이벤트로 반환한다.
TaskManager 한눈에 이해하기
TaskManager는 여러 경로에서 들어오는 기기 동작 요청을 Task로 접수하고, 실행 가능 여부·순서·상태·완료·취소·실패를 공통 규칙으로 관리하는 DeviceAgent 내부 실행 프레임워크다.
이 문서에서 말하는 TaskManager는 새로운 이동·청정·화면 기능을 만드는 모듈이 아니다. 기존 기기 도메인이 기능과 안전 정책을 계속 소유하고, TaskManager는 그 기능이 언제 실행되고, 무엇과 함께 실행되며, 실제로 언제 끝났는지를 관리한다.
해결하는 문제
| 기존 직접 호출에서 생기는 문제 | TaskManager가 제공하는 기준 |
|---|---|
| 앱·PUI·IoT·예약·내부 서비스가 순서와 오류 처리를 각각 구현 | 요청 경로와 무관한 Task·Workflow 실행 계약 |
| API 반환을 이동 도착이나 청정 종료로 오인 | 도착·정지·세션 종료 같은 실제 완료 증거 |
| 여러 기능이 이동·카메라·화면·스피커를 동시에 점유 | 실행 전 상태·자원·호출자 정책 판정 |
| 복합 기능마다 전용 콜백과 상태 변수를 다시 작성 | 검증된 Task를 순차·병렬·조건·대기로 조립 |
| 취소·시간 초과·부분 실패의 의미가 기능마다 다름 | 공통 생명주기, 실패 사유, 취소와 보상 계약 |
| 실행 중인 작업과 실패 지점을 여러 로그에서 역추적 | Task ID와 Workflow ID 기반 이벤트·상태 추적 |
하나의 요청이 처리되는 흐름
핵심은 accepted=true와 COMPLETED를 구분하는 것이다. 요청 접수는 실행 관리의 시작이며, 완료는 각 기기 도메인이 제공하는 최신 상태나 콜백으로 확정한다.
Task와 Workflow
| 단위 | 의미 | 예시 |
|---|---|---|
| Task | 독립적으로 접수·실행·취소·완료 판정할 수 있는 하나의 관리 작업 | 지정 위치 이동, 청정 시작, 화면 전환, 스테이션 복귀 |
| Workflow | 여러 Task의 순서, 의존관계, 조건, 지연과 실패 정책을 가진 실행 묶음 | 이동 완료 → 청정 → 청정 종료 확인 → 복귀 |
| Schedule | Task 또는 Workflow를 정해진 시각이나 실행 조건에 제출하는 예약 계약 | 30분 뒤 선택 공간 청정 Workflow 제출 |
| Completion Evidence | 다음 단계 진행이나 최종 완료를 허용하는 실제 상태 증거 | movement.arrived, cleaning.stopped, 앱 세션 종료 |
책임 경계
| 계층 | 소유하는 책임 | 소유하지 않는 책임 |
|---|---|---|
| 호출자·제품 시나리오 | 실행 목적과 사전 정의 Workflow 생성 | 기기 공통 queue와 물리 완료 판정 |
| 선택적 Planner | 목표 해석과 허용된 capability 조합 | 기기 도메인 안전 정책 우회 |
| TaskManager Core | 접수, Admission, queue, 생명주기, Workflow, 취소와 결과 | 자연어 의미 해석, 이동·청정 기능 자체 구현 |
| 기기 도메인 | 실제 기능 실행, 안전 규칙과 완료·실패 증거 | 여러 요청 경로의 공통 실행 이력 관리 |
| UI·관제·TaskMonitor | 진행, 실패 이유와 사용자 선택 표시 | 실행 결과를 임의로 완료 처리 |
도입 후 달라지는 구조
TaskManager만으로 모든 제품 경험이 자동 생성되는 것은 아니다. 이미 정해진 장면은 앱·관제·제품 시나리오가 Workflow를 만들고, 자유로운 목표 해석이 필요한 경우에만 상위 Planner가 허용된 Task를 조합한다. 어느 경로든 실제 실행은 같은 TaskManager 계약을 사용한다.
전체 목차와 권장 순서
처음 읽을 때는 아래 순서로 핵심 구조를 파악하고, API 필드나 도메인별 사양은 필요한 항목만 찾아보면 된다.
| 순서 | 범위 | 이 부분에서 답하는 질문 |
|---|---|---|
| 1 | 0. 문서 판독 규칙 · 1. TaskManager란 무엇인가 | 구현·목표·제안 상태를 어떻게 구분하고 TaskManager의 책임은 어디까지인가? |
| 2 | 2. AOSP와 SKIX namuh 안에서의 위치 · 3. 전체 구성요소 | Android와 SKIX namuh 제품 구조에서 어느 계층에 있고 구성요소는 어떻게 나뉘는가? |
| 3 | 4. 요청 유입 · 5. 공개 API · 6. 실행 허용 · 7. 실행 정책 | 요청은 어떤 계약으로 들어오고 실행 전에 무엇을 검사하는가? |
| 4 | 8. Task 생명주기 · 9. 실행 런타임 · 10. Workflow · 11. 완료 증거 · 12. 취소 | Task가 접수된 뒤 실제 완료 또는 취소까지 어떻게 진행되는가? |
| 5 | 13. 실패 사유 · 14. 이벤트 · 15. 예약 실행 | 실패, 외부 관찰과 시간 기반 실행은 어떤 계약으로 표현되는가? |
| 6 | 16. 도메인 실행기 · 17. 기기 컨텍스트 · 18. AAR · 19. IoT/MQTT · 20. 선택적 Planner 연동 | 기존 기기 기능과 외부 호출자는 TaskManager에 어떻게 연결되는가? |
| 7 | 21. 관측성 · 22. 영속성·용량 · 23. 보안 · 24. 실패 UX · 25. 인수 기준 | 운영·보안·시험에서 무엇을 확인해야 하는가? |
| 8 | 26. 현재 한계 · 27. 변경 절차 · 28. 참조 색인 | 현재 구현과 목표 사양은 어디까지 다르고, 변경할 때 무엇을 함께 갱신하는가? |
| 9 | 29. Core·Task 규범 · 30. 기존 시스템 호환 · 31. 적합성 판정 | 기능별 필수 필드와 기존 API의 점진 전환 기준은 무엇인가? |
| 10 | 32. 용어집 · 33. 최종 설계 원칙 · 34. 관련 문서 | 용어와 최종 판단 원칙, 세부 문서는 어디서 찾는가? |
빠른 결론
- 기능 호출 성공은 Task 완료가 아니다.
- TaskManager는 기존 기능 위에서 실행을 관리하며 기기 도메인의 안전 정책을 대체하지 않는다.
- 복합 실행은 검증된 Task의 Workflow 조합으로 표현한다.
- 다음 단계는 선행 Task의 실제 완료 증거가 있어야 진행한다.
- 모든 요청 경로는 같은 상태·취소·실패·관측 계약으로 수렴한다.
- Planner 연동은 선택 사항이며 TaskManager Core의 결정론적 실행 책임과 분리한다.
설계 배경과 외부 사례
TaskManager와 유사한 실행 제어 구조는 Android 작업 관리, 로봇 장시간 동작, Fleet Mission, 인프라 제어와 장기 Workflow에서 공통적으로 사용된다. 비교의 목적은 외부 플랫폼 자체를 도입하는 것이 아니라, 작업 수명주기·진행·취소·의존관계·실제 완료 증거가 왜 별도 실행 계층에 필요한지 확인하는 데 있다.
| 설계 참조 | 검증된 실행 원리 | SKIX TaskManager 적용 | 현재 범위 |
|---|---|---|---|
| Android WorkManager | 의존 작업, 상태 전파, 제약, 재시도와 취소 | TaskRecord, TaskPolicy, queue, retry, timeout, schedule |
작업 관리 원리 적용. AndroidX WorkManager 런타임은 사용하지 않음 |
| ROS 2 Actions | 장시간 Goal, Feedback, Cancel과 Result | Task ID, 진행 이벤트, 최종 상태와 취소 명령 | Action 상태 원리 적용. ROS 통신 규격은 범위 밖 |
| Nav2 | 기능 서버 조합, 단계 의존관계와 Recovery | subTasks, 조건, 지연, 제한적 병렬과 실패 정책 |
Workflow 제어 적용. 범용 Behavior Tree와 지속 재계획은 미지원 |
| NVIDIA Isaac Missions | Mission을 Task의 연속으로 관리하고 상태 추적 | Workflow·Step ID, source·trace와 단계 이벤트 | 단일 기기 Workflow 중심. Fleet 배정은 범위 밖 |
| Kubernetes·Borg | Admission, priority, 자원 경쟁과 상태 수렴 | 호출자·상태·CPU·RAM·열·도메인 자원 정책 | 기기 내부 자원 판정 중심. 범용 controller loop는 미지원 |
| Durable Workflow | Step, Wait, Timer, Callback, Retry와 실행 이력 | completion target, watcher, 외부 event, delay와 timeout | 예약 복원 지원. 실행 중 Workflow 전체 replay는 보강 대상 |
SKIX TaskManager는 이 원리를 DeviceAgent의 물리 기능, 안전 정책, 완료 증거와 기존 API 호환성에 맞게 결합한다. 가장 가까운 설명은 작업 수명 관리 + 장시간 물리 실행 상태 + 단계형 Workflow 제어를 하나의 기기 실행 Core로 구성한 것이다.
설계 참조: Android WorkManager 작업 연결, ROS 2 Actions, Nav2 Behavior Tree, NVIDIA Isaac Missions, Microsoft Durable Task.
제1부 · 개념과 구조 — 0~3장은 문서 판독 기준, TaskManager의 책임과 AOSP·DeviceAgent 내부 구성을 정의한다.
0. 문서 판독 규칙
0.1 상태 표기
| 표기 | 의미 | 문서에서의 사용 기준 |
|---|---|---|
| 현재 구현 | MR6 소스에 실행 경로가 존재함 | 클래스, 메서드, 필드와 런타임 경로를 확인함 |
| 코드 검증 | JVM·단위 테스트·빌드 수준에서 확인됨 | 테스트 통과가 실기기 동작을 의미하지는 않음 |
| 실기기 확인 | 특정 기기와 APK 조합에서 실제 증거를 확인함 | 기기, APK 해시나 설정이 바뀌면 재검증 필요 |
| 목표 사양 | 구조적으로 합의한 다음 단계 | 현재 코드에 일부 또는 전부 없을 수 있음 |
| 운영 확장 | Cloud, A2A, 모니터와 상위 서비스 연동 규격 | TaskManager Core의 필수 계약과 분리함 |
| 미검증 | 코드가 있어도 출시 인수 시험이 끝나지 않음 | 제품 완료로 표현하지 않음 |
0.2 가장 중요한 경계
0.3 구현 기준 구성요소
| 범위 | 기준 위치 |
|---|---|
| TaskManager Core | apps/DeviceAgent/app/src/main/java/com/sk/airbot/deviceagent/task/TaskManager.java |
| 메서드 정책 | TaskPolicyRegistry.java, TaskPolicy.java |
| 입력 검증/실행 허용 | TaskBundleValidator.java, TaskCallerPolicy.java, TaskDomainResourcePolicy.java, TaskResourcePolicy.java |
| 제품 상태/동작 제한 | StateManager.java, CmdPolicyManager.java, 도메인별 manager/controller |
| LLM/음성 세션 상태 | LlmManager.java, LlmPipelineObservationBridge.java, MainApi.setLlmStatus 경로 |
| 실행기 | TaskExecutorRegistry.java, TaskExecutorBootstrap.java, 도메인별 *TaskExecutor.java |
| 완료 판정 | TaskCompletionStateStore.java, TaskCompletionWatcher.java, AppSessionCompletionBridge.java, LlmTaskCompletionBridge.java |
| 실패 사유 | TaskReasonContract.java |
| 계획 컨텍스트 | DevicePlanningContextProvider.java |
| 요청 분류 | TaskIngressClassifier.java, TaskIngressClassification.java |
| 모니터링 | TaskMonitorReporter.java, TaskMonitorCommandPoller.java, TaskMonitorCommandBridge.java, TaskMonitorHttpAuth.java |
| 제품 시스템 앱 API | apps/TaskManagerClient/taskmanagerclient/ |
| 외부 계약 | apps/TaskManagerClient/API_SPEC.md |
0.4 규범 키워드
이 문서의 규칙은 중요도에 따라 다음처럼 읽는다.
| 키워드 | 쉬운 설명 | 위반 시 처리 |
|---|---|---|
| MUST / 필수 | 지키지 않으면 TaskManager 계약을 만족하지 못하는 조건 | 출시 차단 또는 명시적 예외 승인 필요 |
| MUST NOT / 금지 | 안전, 중복 실행 또는 호환성 문제 때문에 허용하지 않는 동작 | 구현 수정 전 출시 불가 |
| SHOULD / 권장 | 특별한 이유가 없다면 지켜야 하는 기본 설계 | 예외 이유와 대체 검증을 기록 |
| MAY / 선택 | 제품이나 기능 특성에 따라 적용 가능한 확장 | 적용 여부를 기능 계약에 명시 |
본문의 설명 문장도 31장의 요구사항 ID와 연결되면 규범 효력을 갖는다. 소스에 클래스나 메서드가 있다는 사실만으로 MUST 충족을 선언하지 않는다.
0.5 독자별 권장 읽기 순서
| 독자 | 먼저 읽을 장 | 얻어야 하는 답 |
|---|---|---|
| 기획/리더 | 1, 2, 24, 29, 30 | 무엇이 달라지고 기존 시스템을 어떻게 보호하는가 |
| 제품 시스템 앱 개발자 | 5, 18, 30 | 어떤 요청을 보내고 어떤 응답·콜백을 받아야 하는가 |
| DeviceAgent/기기 도메인 개발자 | 6~13, 16, 29 | 기능을 Task로 연결할 때 무엇을 구현해야 하는가 |
| Planner/Cloud 개발자 | 17, 20, 29 | 어떤 기기 사실과 capability를 사용하고 언제 재계획하는가 |
| QA/SQE | 11~15, 21, 25, 30, 31 | 실제 완료와 호환성을 어떤 증거로 판정하는가 |
| 운영/릴리스 | 19, 21~23, 25, 30 | 배포, 감시, 보안과 원복을 어떻게 수행하는가 |
0.6 사양과 구현의 우선순위
- 제품 안전 정책과 승인된 요구사항이 최우선이다.
- 이 사양서는 공개 계약과 인수 기준의 기준점이다.
- DeviceAgent 구현은 이 사양의 적합성을 코드와 시험 증거로 입증해야 한다.
- 사양과 구현이 다르면 차이를 요구사항 또는 결함으로 관리하고, 승인 없이 구현 동작을 사양으로 간주하지 않는다.
1. TaskManager란 무엇인가
TaskManager는 기기 기능을 호출하는 또 하나의 API 래퍼가 아니다. 여러 경로에서 들어온 기기 작업을 동일한 실행 단위와 상태 모델로 관리하는 DeviceAgent 내부 실행 제어 계층이다.
기존 구조에서는 호출자가 기능별 API를 직접 호출하고, 다음 작업의 시작 시점, 실패 대응, 실제 취소 여부와 완료 판정 콜백을 각각 구현해야 했다. 단일 명령에는 단순하지만 기능과 요청 경로가 늘수록 같은 제어 코드가 여러 앱과 서비스에 흩어진다.
TaskManager 도입 후 호출자는 다음을 구조화해 제출한다.
| 실행 계약이 답해야 하는 질문 | 대표 필드 |
|---|---|
| 무엇을 실행하는가? | taskMethod |
| 어디에서 온 요청인가? | source |
| 어느 실행 대기열을 사용하는가? | queue |
| 얼마나 우선하는가? | priority |
| 어떻게 결과를 반환하는가? | executionMode |
| 언제 실제 완료로 판단하는가? | completionTarget |
| 취소할 때 무엇을 실행하는가? | cancelMethod |
| 실패 후 무엇을 복구하는가? | compensationMethod |
| 여러 단계는 어떤 관계를 가지는가? | subTasks, trigger, conditions, parallelGroup |
TaskManager는 이 정보를 TaskRecord로 관리한다. 실제 실행은 기존 기기 도메인 실행기에 위임하고, 콜백과 상태 증거를 이용해 최종 상태를 확정한다.
1.1 한 문장 정의
TaskManager는 기존 DeviceAgent 기능을 Task와 Workflow로 표준화해 실행 순서, 상태, 자원 경쟁, 취소, 실패와 완료 증거를 공통으로 관리하는 SKIX namuh 제품 실행 프레임워크다.
1.2 무엇이 달라지는가
| 항목 | 도입 전 | 도입 후 |
|---|---|---|
| 기능 호출 | 호출자가 기기 도메인 API를 직접 호출 | submitTask 또는 submitWorkflow로 제출 |
| 순차 실행 | 호출자 코드에서 콜백을 직접 연결 | subTasks 순서와 단계 상태로 관리 |
| 병렬 실행 | 호출자가 스레드 생성과 결과 취합을 직접 구현 | parallelGroup과 실패 정책으로 표현 |
| 상태 | 기능별 상태값 또는 콜백 | TaskRecord의 공통 생명주기로 관리 |
| 경쟁 | 앱마다 별도 차단 로직 구현 | 대기열, 우선순위와 도메인 자원 정책으로 실행 허용 판정 |
| 취소 | 기능별 중지 API를 직접 찾아 호출 | Task 취소와 cancelMethod 연결 |
| 완료 | 메서드 반환을 실제 성공으로 오해하기 쉬움 | completionTarget에 해당하는 실제 완료 증거 대기 |
| 실패 | 자연어 메시지 또는 모듈별 오류 | 실패 사유, 복구 가능성과 권장 조치로 구조화 |
| 예약 | 예약 등록과 실제 실행이 섞이기 쉬움 | 예약 등록과 실행 시점의 허용 판정을 분리 |
| 관찰 | 여러 로그를 수동으로 조합 | Task, 대기열, Workflow와 단계 이벤트를 하나의 실행으로 연결 |
1.3 TaskManager가 하지 않는 일
- 자연어 원문, UI 선택과 시스템 이벤트를 분류하거나 제품 목표로 해석하지 않는다.
- 등록되지 않은 기능을 임의로 만들어 실행하지 않는다.
- 이동 경로, 청정 알고리즘, 보안 순찰 알고리즘을 대체하지 않는다.
- 센서 원시 데이터의 의미를 자체 추론하지 않는다.
- 모든 실패를 Cloud에 보내지 않는다.
- 제품의 반복 생활 스케줄 DB를 TaskManager 단기 지연 실행과 동일하게 취급하지 않는다.
- Android 플랫폼 공개 SDK인 것처럼 외부 일반 앱에 무제한 노출하지 않는다.
2. AOSP와 SKIX namuh 안에서의 위치
2.1 패키징 위치와 아키텍처 역할
DeviceAgent는 Android 빌드 관점에서 /system/priv-app에 배치되는 애플리케이션 패키지다. platform 인증서로 서명되고 android.uid.system을 사용하며, persistent 애플리케이션의 바운드 서비스로 실행된다. 따라서 일반 사용자 앱과 같은 제품 기능 화면이 아니라, 시스템 권한으로 여러 기기 기능을 연결하는 상시 실행 서비스다.
패키징 위치와 아키텍처 역할은 서로 다른 축이다. DeviceAgent는 앱 프로세스에 배치되지만, TaskManager와 공개 계약은 여러 제품 앱이 공통으로 사용하는 실행 기반을 제공한다. 이 역할을 SKIX namuh Product Framework Layer로 정의한다.
| 구분 | 실제 위치와 역할 |
|---|---|
| Android 패키징 | /system/priv-app의 com.sk.airbot.deviceagent 애플리케이션 |
| 권한과 생명주기 | platform 서명, android.uid.system, persistent 서비스, signature 권한 |
| 프로세스 | DeviceAgent 전용 앱 프로세스. system_server 내부가 아님 |
| 제품 아키텍처 | 제품 앱과 기기 도메인 사이의 SKIX namuh Product Framework Layer |
| 공개 진입점 | TaskManagerClient AAR, IDeviceControl Binder 계약과 MainApi |
| 실행 책임 | TaskManager Core, 실행기, 기존 기기 도메인과 완료 증거 연결 |
2.2 SKIX namuh Product Framework Layer
이 계층은 특정 화면이나 하나의 제품 기능을 구현하지 않는다. 제품 앱, IoT, PUI, 예약과 내부 서비스가 같은 기기 기능을 호출할 때 공통으로 필요한 권한, 실행 순서, 상태, 취소, 실패와 완료 계약을 제공한다.
| 계층 | 담당 범위 |
|---|---|
| SKIX 제품·시스템 앱 | 사용자 경험, 제품 시나리오와 실행 요청 생성 |
| TaskManagerClient AAR | 타입 기반 요청 생성, Binder 연결, 조회·취소와 콜백 API |
| DeviceAgent 공개 진입점 | 권한 확인, 기존 API 호환과 관리 경로 선택 |
| TaskManager Core | 실행 허용, 대기열, Workflow, 예약, 생명주기와 결과 관리 |
| 기기 도메인·완료 어댑터 | 기존 기능 호출과 실제 완료·실패 증거 연결 |
이 구조에서 DeviceAgent는 구현 형태로는 시스템 특권 앱 서비스이고, 제품 구조에서는 공통 실행 프레임워크다. 두 설명은 서로 다른 관점의 위치를 나타낸다.
2.3 AOSP Framework와의 경계
| 표현 | 이 사양에서의 의미 |
|---|---|
| Android Application Framework | frameworks/base, system_server, Android 공개·비공개 API와 시스템 서비스 |
| SKIX namuh Product Framework Layer | AOSP 메커니즘 위에서 여러 제품 앱과 기기 기능이 공유하는 제품 전용 실행 계층 |
| TaskManager Core | DeviceAgent 프로세스 내부의 실행 관리 런타임 |
| TaskManagerClient AAR | 제품 시스템 앱에 제공하는 타입 기반 Java 진입점 |
TaskManager는 AOSP SystemService가 아니다. frameworks/base나 system_server에 등록되지 않으며, AOSP의 Binder, 서비스 생명주기와 시스템 API를 사용해 DeviceAgent 프로세스 안에서 동작하는 SKIX namuh 제품 실행 프레임워크다. 따라서 Android 공개 SDK와 같은 범용 플랫폼 API가 아니라, 플랫폼 서명과 제품 권한 경계 안에서 사용하는 내부 프레임워크로 구분한다.
2.4 AOSP 구성요소 활용
| AOSP 구성요소 | TaskManager 사용 목적 |
|---|---|
| Binder/AIDL | 제품 시스템 앱과 DeviceAgent 사이 IPC |
| Bundle | 요청, 결과와 콜백을 전달하는 타입 기반 묶음 |
| 서비스 생명주기 | DeviceAgent 런타임 생명주기 |
Executor/Future |
대기열 실행, 시간 제한과 취소 |
AlarmManager/PendingIntent |
예약 Task의 실행 시점 진입 보조 |
BroadcastReceiver |
예약된 실행 허용 절차 재진입 |
SystemProperties |
런타임 활성화, 영속성과 모니터 설정 |
| 파일 I/O·JSON | Task·예약 상태 스냅숏 저장 |
3. 전체 구성요소
3.1 구성요소와 책임
| 구성요소 | 책임 | 대표 소스 |
|---|---|---|
| 공개 진입점 | 제어 메서드 처리와 기존 시스템 호환 경로 선택 | MainApi, TaskManager.handleControlMethod() |
| 별칭 변환기 | Cloud·기존 메서드 별칭을 표준 메서드로 변환 | TaskMethodAliasResolver |
| 입력 검증기 | 메서드별 입력 구조 검증 | TaskBundleValidator |
| 호출자 정책 | 요청 출처에 허용된 우선순위인지 확인 | TaskCallerPolicy |
| 상태 정책 | 현재 주 상태와 차단 상태 확인 | TaskManager.checkStateCondition() |
| 도메인 자원 정책 | 카메라, 이동 기반부와 전면 앱 세션의 충돌 차단 | TaskDomainResourcePolicy |
| 시스템 자원 정책 | CPU, RAM과 발열 상태를 바탕으로 실행 허용 판정 | TaskResourcePolicy |
| 기기 도메인 정책 | LLM, 배터리, AMR, 개인정보 보호, 오류와 현재 동작을 바탕으로 최종 실행 판정 | CmdPolicyManager, StateManager, 도메인별 manager |
| 실행 정책 목록 | 실행 방식, 대기열, 우선순위, 시간 제한, 재시도, 취소와 보상 동작 결정 | TaskPolicyRegistry |
| 런타임 Core | 실행 기록, 대기열, Workflow, 예약, 조회와 제어 | TaskManager |
| 실행기 등록부 | taskMethod를 실행 어댑터에 연결 |
TaskExecutorRegistry, TaskExecutorBootstrap |
| 도메인 어댑터 | 표준 요청을 기존 도메인 호출 구조로 변환 | MovementTaskExecutor 등 |
| 완료 상태 저장소 | 도메인 콜백을 공통 완료 조건에 맞게 저장 | TaskCompletionStateStore |
| 완료 감시기 | 대상·공간·시점·안정화 조건이 충족될 때까지 대기 | TaskCompletionWatcher |
| 실패 사유 계약 | 하위 오류를 구조화된 실패 사유로 정규화 | TaskReasonContract |
| 컨텍스트 제공자 | Planner와 운영 도구에 기기 상태 스냅숏 제공 | DevicePlanningContextProvider |
| 이벤트·모니터 | Task 이벤트 전달, 연결 상태 보고와 명령 조회 | TaskMonitorReporter, TaskMonitorCommandPoller |
| Client AAR | 타입 기반 요청 생성기, 조회, 취소와 콜백 API 제공 | TaskManagerClient |
3.1.1 처음 보는 사람을 위한 구성요소 지도
| 역할 묶음 | 구성요소 | 쉬운 한 줄 설명 |
|---|---|---|
| 접수 | 공개 진입점 | PUI, 앱, IoT, Cloud 요청을 받아 기존 실행과 Task 실행 중 어느 경로로 보낼지 결정한다. |
| 형식 변환 | 별칭 변환기, 도메인 어댑터 | 서로 다른 기능 이름과 입력값을 표준 Task 형식과 기존 도메인 형식 사이에서 변환한다. |
| 실행 전 심사 | 입력 검증기, 호출자·상태·자원 정책 | 요청이 올바르고 현재 기기에서 안전하게 시작할 수 있는지 확인한다. |
| 실행 조정 | 실행 정책 목록, 런타임 Core | 여러 작업의 순서, 우선순위, 대기열, 시간 제한과 병렬 실행을 관리한다. |
| 작업 배정 | 실행기 등록부 | taskMethod에 맞는 DeviceAgent 기능 담당자를 찾아 연결한다. |
| 완료 확인 | 완료 상태 저장소, 완료 감시기 | 함수 호출이 아니라 실제 이동·청정·재생·세션 종료를 확인한다. |
| 실패 기록 | 실패 사유 계약 | 실패 원인을 공통 코드와 설명으로 바꿔 안내와 복구 판단에 사용한다. |
| 상태 제공 | 컨텍스트 제공자, 이벤트·모니터 | 현재 기기 상태와 Task 진행 상황을 상위 서비스와 운영 화면에 제공한다. |
| 외부 사용 창구 | Client AAR | 다른 제품 시스템 앱이 내부 구현을 몰라도 표준 Task API를 호출하게 한다. |
이 구조에서 TaskManager는 실제 기기 기능을 수행하지 않는다. 요청 접수, 실행 순서, 상태와 완료를 관리하는 실행 조정자다. 이동과 청정 같은 실제 작업은 기존 기기 도메인이 계속 수행한다.
3.2 소유권 경계
책임 경계는 0.2 가장 중요한 경계의 구조도를 따른다. Planner는 목표와 계획, TaskManager는 실행 생명주기, 기기 도메인은 실제 동작과 물리 상태를 소유한다. Monitor는 이 상태를 표시하고 허용된 제어를 전달하지만, Task의 최종 상태를 임의로 확정하지 않는다.
3.3 스레드와 대기열의 기본 모델
- 대기열별 실행기는 같은 대기열 안의 작업 순서를 관리한다.
- 우선순위가 높은 작업을 먼저 실행하고, 우선순위가 같으면 제출 순서를 유지한다.
- 상위 Workflow는
workflow대기열에서 전체 흐름을 관리한다. - 병렬 하위 단계는 각 도메인 대기열에서 실행하며, 상위 Workflow가 결과를 취합한다.
runningManagedTask스레드 로컬 보호 장치는 TaskManager가 기존MainApi를 다시 호출할 때 대기열에 재귀 진입하는 것을 막는다.- 기본 대기열 용량은
64, 실행 기록 보존 상한은100이다.
제2부 · 요청 계약과 실행 허용 — 4~7장은 요청이 들어오는 경로, 공개 API, 실행 허용 판정과 정책을 설명한다.
4. 요청 유입과 유형 분류
4.1 지원 요청 출처
| 요청 출처 | 의미 | 일반적인 사용 예 |
|---|---|---|
APP |
제품 앱 요청 | 런처·시스템 앱 |
PUI |
물리 UI 요청 | 버튼·터치 제어 |
IOT |
IoT/MQTT 요청 | 원격 명령 |
SCHEDULE |
제품 예약 실행 | Wakeup·Welcome·청정 스케줄 |
SENSOR |
센서 기반 요청 | 안전 이벤트·상태 조건 |
CLOUD |
Cloud Planner 요청 | A2A Workflow |
ONDEVICE |
온디바이스 Agent 요청 | 기기 내 Planner·Bridge |
API |
내부 API 클라이언트 | SDK 호출 |
AUTONOMOUS |
기기 자율 판단 | 기기 내 복구·상태 관찰 |
INTERNAL |
DeviceAgent 내부 요청 | 모듈 전달·생명주기 명령 |
VOICE |
음성 요청 | 온디바이스 음성 Agent |
UNKNOWN |
출처가 없거나 불명확한 요청 | 제한적 호환 입력 |
4.2 신호 유형
TaskIngressClassifier는 들어오는 모든 메서드를 Task로 만들지 않는다.
| 신호 유형 | Task 관리 여부 | 처리 경로 | 의미 |
|---|---|---|---|
COMMAND_TASK |
true | submit_task |
실제 기기 상태를 바꾸는 명령 |
TASK_CONTROL |
false | task_manager_api |
조회, 취소와 대기열 제어 |
PROGRESS_UPDATE |
false | update_task_progress |
실행 중 진행률 갱신 |
RESULT_UPDATE |
false | update_task_result |
기기 도메인 결과 콜백 |
SENSOR_DATA |
false | state_or_resource_update |
상태·센서 스냅숏 갱신 |
TRIGGER |
false | policy_trigger |
정책 판정 후 Task를 만들 수 있는 이벤트 |
EVENT_CALLBACK |
false | event_callback |
기기 도메인 콜백·이벤트 |
UNKNOWN |
false | reject |
분류할 수 없는 입력 |
핵심 원칙은 명령과 관찰을 분리하는 것이다. 센서 콜백을 다시 구동 Task로 감싸면 순환 호출과 중복 실행이 생길 수 있다.
4.3 MainApi의 세 경로
method가 TaskManager 제어 메서드이면handleControlMethod()가 직접 처리한다.forceTaskManager=true이거나 Task 관리 대상 메서드이면 관리 실행 경로를 사용한다.- TaskManager 대상이 아니거나 호환성이 필요한 호출은 기존 경로를 유지한다.
이 구조는 기존 기능을 한 번에 전부 교체하지 않고 점진적으로 Task 계약에 편입하기 위한 호환 경계다.
5. 공개 제어 API
현재 TaskManager.handleControlMethod()와 TaskManagerClient가 공유하는 제어 메서드는 17개다.
| 메서드 | 주요 입력 | 주요 출력 | 역할 |
|---|---|---|---|
submitTask |
taskMethod, 매개변수 |
accepted, taskId, 결과 |
단일 Task 제출 |
submitWorkflow |
workflowName, subTasks |
상위 Task와 단계 상태 | 복합 Workflow 제출 |
scheduleTask |
Task와 trigger |
scheduleId, 상태 |
단일 Task 지연 등록 |
scheduleWorkflow |
Workflow와 trigger |
scheduleId, 상태 |
Workflow 지연 등록 |
getScheduledTasks |
상태·출처·개수 제한 | scheduledTasks |
예약 목록 조회 |
cancelScheduledTask |
scheduleId, 사유 |
취소 상태 | 예약 취소 |
runDueScheduledTasks |
nowMs, 개수 제한 |
실행 허용·건너뜀 결과 | 실행 시점이 된 Task 재진입 |
getTaskStatus |
taskId |
TaskRecord 상세 |
Task 상세 조회 |
listTasks |
조회 조건 | tasks |
Task 목록 조회 |
getQueueStatus |
대기열 | 대기열 스냅숏 | 대기열별 실행·대기 상태 |
updateTaskProgress |
Task ID·진행률·단계·메시지 | 갱신된 기록 | 외부 진행률 반영 |
cancelTask |
Task ID·사유 | 취소 결과 | 개별 Task 취소 |
clearPendingTasks |
대기열 | 처리 건수 | 대기 Task만 정리 |
cancelQueue |
대기열·실행 중 포함 여부 | 처리 건수 | 대기열 단위 취소 |
getTaskManagerStatus |
없음 | 운영 지표·대기열 | TaskManager 상태 조회 |
getDevicePlanningContext |
없음 | 컨텍스트 스냅숏 | 현재 기기 상태 조회 |
classifyTaskIngress |
Task 메서드·신호 유형 | 분류 결과 | 요청 유형 판정 조회 |
위 17개 메서드는 현재
TaskManager의 제어 분기와TaskManagerClient공개 상수에 모두 존재한다. 출시할 때마다 양쪽 목록과 실제 처리 분기를 교차 점검해야 한다.
5.1 submitTask 최소 요청
{
"method": "submitTask",
"forceTaskManager": true,
"taskMethod": "setMoveTo",
"source": "APP",
"requestId": "move-bedroom-001",
"traceId": "trace-001",
"positionId": "5",
"positionName": "안방",
"completionTarget": "movement.arrived",
"timeoutMs": "120000"
}
5.2 submitWorkflow 최소 요청
{
"method": "submitWorkflow",
"forceTaskManager": true,
"workflowName": "room_clean_return",
"source": "APP",
"requestId": "wf-room-clean-001",
"traceId": "wf-room-clean-001",
"subTasks": [
{
"stepId": "move-bedroom",
"taskMethod": "setMoveTo",
"positionId": "5",
"positionName": "안방",
"completionTarget": "movement.arrived"
},
{
"stepId": "clean-bedroom",
"taskMethod": "setAirCleanerOperation",
"action": "1",
"mode": "0",
"completionTarget": "cleaning.stopped"
},
{
"stepId": "return-station",
"taskMethod": "returnToStation",
"completionTarget": "movement.stationCharging"
}
]
}
5.3 공통 요청 필드
| 필드 | 타입 | 필수성 | 의미 |
|---|---|---|---|
method |
String | 필수 | 제어 메서드 |
forceTaskManager |
Boolean | 권장 | 속성과 관계없이 TaskManager 경로를 강제 |
taskMethod |
String | Task 필수 | 실행할 표준 기능 메서드 |
workflowName |
String | Workflow 필수 | Workflow 식별 이름 |
subTasks |
List<Bundle> | Workflow 필수 | 순차 단계 또는 병렬 그룹 |
source |
String | 권장 | 요청 유입원 |
requestId |
String | 강력 권장 | 멱등성과 중복 등록 방지 식별자 |
traceId |
String | 강력 권장 | 계층 간 실행 추적 식별자 |
queue |
String | 선택 | 외부 계약의 queue 필드 |
queueKey |
String | 내부 변경 | 현재 정책 변환기가 읽는 변경 키 |
priority |
String | 선택 | BACKGROUND~EMERGENCY |
executionMode |
String | 선택 | direct, queued_wait, async |
timeoutMs |
String/Long | 선택 | Task 런타임 시간 제한 |
strictValidation |
Boolean | 권장 | 메서드 스키마 강제 여부 |
preemptPolicy |
String | 선택 | 기존 Task 처리 정책 |
cancellable |
Boolean | 선택 | 취소 가능 여부 변경 |
stateAware |
Boolean | 선택 | 상태 기반 실행 허용 판정 적용 여부 |
cancelMethod |
String | 선택 | 취소할 때 실행할 메서드 |
compensationMethod |
String | 선택 | 실패 뒤 실행할 보상 동작 메서드 |
requireMainState |
String/Int | 선택 | 필요한 주 상태 |
checkBlockedStatus |
Boolean | 선택 | 차단 상태 확인 여부 |
resourcePolicyEnabled |
Boolean | 선택 | 시스템 자원 정책 활성화 |
requiredResources |
List<String> | 선택 | 카메라·화면·이동 등 필수 자원 |
completionTarget |
String | 선택 | 실제 완료 증거 종류 |
completionTimeoutMs |
String/Long | 선택 | 완료 증거 대기 시간 제한 |
completionStableMs |
String/Long | 선택 | 완료 증거 안정 유지 시간 |
queue와 queueKey는 계층별 명칭 차이가 남아 있다. AAR builder는 queue를 쓰지만 TaskPolicyRegistry.resolve()는 직접 변경값으로 queueKey를 읽는다. 외부 계약은 queue를 표준 이름으로 유지하고 DeviceAgent 경계에서 별칭을 정규화해야 한다.
5.4 생략 필드의 기본값과 적용 순서
요약: TaskManager의 기본값은 요청 생성기 한 곳에서 일괄 입력되지 않는다. 호출 경로가 자동으로 넣는 값, 메서드 정책 목록이 채우는 값, Workflow·예약 런타임이 계산하는 값과 도메인 실행기가 보완하는 값이 순서대로 결합된다. 따라서 “필드를 생략해도 된다”는 말은 어느 계층이 어떤 값으로 보완하는지 계약에 고정돼 있다는 뜻이어야 한다.
5.4.1 기본값 결정 우선순위
실행값은 다음 순서로 결정된다.
- 호출자가 명시한 값: 허용된 변경 필드는 요청값을 우선 사용한다.
- 호출 경로의 정규화·자동 삽입: AAR, Cloud 어댑터, Task Monitor가 제어 메서드와 일부 메타데이터를 넣는다.
- 메서드별 명시 정책:
TaskPolicyRegistry의 exact policy가 실행 방식, 대기열, 우선순위, 시간 제한, 재시도, 취소와 보상 동작을 제공한다. - 등록되지 않은 메서드의 추정 정책: 메서드 이름으로 임시 fallback policy를 만든다. 이는 호환 안전망이며 출시 기능의 정식 사양으로 사용하면 안 된다.
- Workflow·예약 런타임 기본값: Workflow 이름, 병렬 그룹 정책, 단계 지연, 예약 유형과 실행 허용 옵션을 보완한다.
- 도메인 실행기 기본값: 이동, 청정, Security 등 실제 기능이 안전한 호출 형식이나 완료 조건을 추가로 정규화한다.
- 시스템 속성 기본값: 엄격 검증, 자원 정책, 영속성, 대기열 크기 같은 운영값을 최종 적용한다.
TaskRecord의 taskId는 호출자가 보내지 않아도 <taskMethod>-<sequence> 형식으로 생성된다. 예약 ID도 scheduled-<sequence> 형식으로 생성된다. 반면 requestId와 traceId는 자동 생성되지 않는다. 내부 Task ID가 생긴다는 사실을 외부 멱등성과 분산 추적이 확보된 것으로 해석하면 안 된다.
5.4.2 호출 경로별 자동 입력
| 호출 경로 | 생략 시 자동 입력 | 자동 입력하지 않는 주요 값 | 의미 |
|---|---|---|---|
TaskSubmitRequest AAR |
method=submitTask, forceTaskManager=true, builder 인자의 taskMethod |
source, requestId, traceId, 완료 조건 |
최소 타입 안전성은 제공하지만 운영 메타데이터는 호출자 책임 |
TaskWorkflowRequest AAR |
method=submitWorkflow, forceTaskManager=true, builder 인자의 workflowName, subTasks |
source, requestId, traceId, 단계 ID와 완료 조건 |
빈 단계 목록은 build()에서 거절 |
AAR scheduleTask/Workflow |
위 값과 scheduleKind=deferred_task |
실제 trigger 시각 |
trigger가 없으면 Core에서 missing_schedule_trigger 거절 |
| Cloud Device Task 어댑터 | method=submitTask, forceTaskManager=true, source 인자 생략 시 source=CLOUD |
requestId, traceId, 메서드별 필수 입력 |
Cloud payload를 Task 계약으로 정규화 |
| Task Monitor | forceTaskManager=true, source 생략 시 CLOUD, queue 생략 시 default 또는 routine, dryRun=true, executorDryRun=true |
실제 실행을 위한 dryRun=false |
모니터 기본은 물리 동작 없는 안전 시험 |
raw Bundle |
자동 입력 없음 | 제어 method, taskMethod, source와 상관관계 필드 |
가장 유연하지만 누락·별칭 오류 위험이 가장 큼 |
forceTaskManager를 raw 요청에서 생략하면 요청 자체의 기본값은 false다. 다만 현재 시스템 속성 persist.sys.deviceagent.taskmanager.enable의 기본값이 true이므로 Core는 활성화된다. AAR가 forceTaskManager=true를 넣는 이유는 시스템 속성 상태와 무관하게 관리 경로를 명시하기 위해서다.
5.4.3 공통 실행 정책 기본값
| 필드 | 생략 시 현재 동작 | 적용 주체 | 주의점 |
|---|---|---|---|
source |
일반 raw 요청은 UNKNOWN, Cloud 어댑터·Monitor는 CLOUD |
TaskSource.from() 또는 호출 어댑터 |
UNKNOWN은 호출자 권한과 운영 분석의 의미를 약화시킴 |
executionMode |
메서드별 exact policy 사용 | TaskPolicyRegistry |
조회는 주로 DIRECT, 이동·청정·세션은 주로 ASYNC, 상태 변경은 주로 QUEUED_WAIT |
queueKey |
메서드별 exact policy 사용 | TaskPolicyRegistry |
현재 AAR의 queue 변경값이 Core의 queueKey 읽기와 불일치할 수 있음 |
priority |
메서드별 exact policy 사용 | TaskPolicyRegistry |
잘못된 문자열도 정책값으로 복귀하며 별도 오류를 내지 않음 |
timeoutMs |
exact policy 값, 일반 fallback 30초 | TaskPolicyRegistry |
조회 3~5초, 이동 120초, 청정·interaction 1200초처럼 메서드별 차이가 큼 |
retry |
대부분 0, setConfig 1 |
TaskPolicyRegistry |
자동 재시도 가능 기능은 명시 정책으로 제한해야 함 |
cancellable |
메서드별 정책값 | TaskPolicyRegistry |
이동·청정·AI·일부 장기 세션은 true, 조회·일반 상태 변경은 주로 false |
stateAware |
현재 exact/fallback policy 모두 true | TaskPolicyRegistry |
requireMainState나 checkBlockedStatus가 없으면 추가 상태 조건 검사는 발생하지 않음 |
cancelMethod |
메서드별 정책 또는 대기열별 기본 취소 메서드 | TaskPolicyRegistry |
이동은 stopMovement, AI는 LLM 상태 변경, 청정은 청정 stop 계약 사용 |
compensationMethod |
exact policy에 정의된 경우만 사용, 일반 fallback은 없음 | TaskPolicyRegistry |
취소 동작과 실패 보상 동작은 동일하지 않음 |
preemptPolicy |
append |
TaskManager.applyPreemptPolicy() |
생략하면 기존 대기·실행 Task를 취소하지 않고 뒤에 추가 |
strictValidation |
false | 요청값 또는 시스템 속성 | false이면 메서드 필수 매개변수 오류가 실행기까지 늦게 전달될 수 있음 |
resourcePolicyEnabled |
false | 요청값 또는 시스템 속성 | false여도 Vision·Security 등 명확한 도메인 자원 충돌 검사는 별도로 수행됨 |
bypassCallerPolicy |
false | TaskCallerPolicy |
true는 특권 우회이므로 일반 호출자에게 노출하면 안 됨 |
requireMainState |
조건 없음 | TaskManager |
값이 있을 때만 현재 주 상태와 비교 |
checkBlockedStatus |
false | TaskManager |
생략하면 StateManager.checkBlockedStatus() 추가 검사를 요청하지 않음 |
requiredResources |
빈 목록. 단, rotateInPlace는 movement_base, observeVisionSemantics는 movement_base와 camera를 내부 추가 |
TaskDomainResourcePolicy |
도메인 고정 자원과 호출자 추가 자원을 합쳐 충돌 판정 |
completionTarget |
공통 기본값 없음. 도메인 실행기가 지원 메서드에 한해 결정 | 각 도메인 실행기 | 명시값도 실행기가 지원하지 않으면 도메인 기본값 또는 비대기 동작으로 바뀔 수 있음 |
completionTimeoutMs |
timeoutMs, 그것도 없으면 메서드 정책 시간 제한 |
TaskCompletionWatcher |
최종값은 최소 1초. 0 이하이면 일반 완료 대기 기본 30초로 복귀 |
completionStableMs |
500ms | TaskCompletionWatcher |
0을 명시하면 한 번 관찰된 완료 증거를 즉시 인정 |
completionKey |
공통 기본값 없음 | 도메인 실행기 | TTS와 UI는 일부 대체 키를 찾지만 앱 세션은 명시 키 필수 |
preemptExisting |
Core 해석 없음 | AAR builder에만 필드 존재 | 현재 선점 효과를 원하면 preemptPolicy를 사용해야 함 |
executorDryRun |
실제 AAR/raw 경로 false, Task Monitor 경로 true | 실행기·Monitor 어댑터 | Monitor에서 생략했다고 실기기 동작이 실행되는 것이 아님 |
등록되지 않은 메서드의 fallback은 일반적으로 timeoutMs=30000, retry=0, stateAware=true를 사용한다. 이름이 get, is, Info, Version, Dump 계열이면 DIRECT로, 그 외에는 ASYNC로 추정한다. 이름에 stop, reset, error, emergency가 들어가면 EMERGENCY로 추정할 수 있으므로, 외부의 source 누락은 UNKNOWN이 되어 호출자 정책에서 거절될 수 있다. 이름 기반 fallback은 개발 중 호환용이지 기능 등록을 대신하지 않는다.
5.4.4 Workflow와 예약 기본값
| 필드 | 생략 시 현재 동작 | 적용 주체 | 주의점 |
|---|---|---|---|
workflowName |
raw Core 요청은 workflow; AAR builder는 빈 이름 거절 |
Workflow 런타임 / AAR | 운영에서는 충돌 없는 의미 이름을 명시해야 함 |
| Workflow queue | 항상 workflow로 고정 |
ensureWorkflowPolicy() |
하위 단계는 각자의 도메인 대기열·정책 사용 |
| Workflow 실행 방식·우선순위 | 이름으로 해석한 정책 사용. 일반 이름은 보통 ASYNC·NORMAL | TaskPolicyRegistry |
제품 Workflow는 실행 방식과 반환 시점 계약을 명시적으로 고정해야 함 |
| Workflow timeout | 각 단계 timeout과 after_step.delayMs의 합 이상으로 계산 |
calculateWorkflowTimeoutMs() |
병렬 그룹은 자식 timeout의 최댓값을 사용 |
Workflow cancellable |
true | ensureWorkflowPolicy() |
실제 취소 성공은 실행 중 자식과 취소 메서드의 증거에 달림 |
단계 trigger·conditions |
둘 다 없으면 즉시 실행 | Workflow 런타임 | 조건부 단계가 필요하면 구조화 필드를 명시해야 함 |
after_step.delayMs |
0ms | Workflow 런타임 | 음수는 거절, 0이면 선행 단계 완료 직후 실행 |
조건 step_output_equals.onFalse |
fail |
Workflow 런타임 | skip을 원하면 명시해야 함 |
병렬 groupId |
parallelGroup-<stepIndex> |
병렬 그룹 런타임 | 관측성과 재시도 추적을 위해 명시 권장 |
병렬 joinPolicy |
all_success |
병렬 그룹 런타임 | 현재 구현은 모든 자식 종료를 기다리며 다른 join 동작을 별도로 분기하지 않음 |
병렬 failurePolicy |
fail_parent |
병렬 그룹 런타임 | continue_on_failure, partial_success가 필요하면 명시 |
scheduleKind |
deferred_task |
예약 런타임 / AAR | 다른 값은 unsupported_schedule_kind로 거절 |
requireFreshDeviceContext |
false | 예약 실행 허용 단계 | false이면 실행 직전 컨텍스트 새로고침을 요구하지 않음 |
blockWhenTaskManagerBusy |
false | 예약 실행 허용 단계 | fresh context가 없거나 옵션이 false이면 busy만으로 차단하지 않음 |
requiresCloudDecision |
false | 예약 결과 계약 | 실패·미실행 뒤 Cloud 판단이 필요하면 명시 |
missedRunGraceMs |
0 | 예약 실행 허용 단계 | 0은 만료 유예 검사를 사용하지 않는다는 뜻 |
runDueScheduledTasks.nowMs |
현재 시스템 시각 | 예약 런타임 | 시험에서 과거·미래 시각을 주입할 때만 명시 |
조회·실행 limit |
100, 최종 범위 1~100 | 예약·Task 목록 런타임 | AAR scheduler 자체의 주기 실행 묶음 상한 기본은 별도로 20 |
reportNonDueSkips |
true | 예약 런타임 | 아직 시점이 안 된 항목도 skipped 결과에 포함 |
예약 취소 reason |
cancel scheduled task |
예약 런타임 | 사용자·운영 원인을 보존하려면 구체적으로 명시 |
5.4.5 도메인 실행기가 보완하는 값
| 도메인 | 생략 시 보완되는 값 | 적용 범위 |
|---|---|---|
이동 setMoveTo |
isAirsensor=false, isAirSensor=false, isAppCall=false; 이동 시간 제한 기본 120초 |
관리 이동 실행기 |
| 스테이션 복귀 | 이미 도킹 중이면 이동 명령 없이 완료 결과 반환, 아니면 movement.stationCharging 관찰 |
관리 이동 실행기 |
| 청정 | action=시작, mode=기본 청정, speed=0, ai=false; 시간 제한 기본 1200초 |
관리 청정 실행기 |
| 청정 완료 조건 | 정지 명령 또는 기본 청정은 cleaning.stopped, 그 외 시작 청정은 cleaning.reportDone |
관리 청정 실행기 |
| 청정 최소 수행 시간 | cleanMinTimeMs가 없으면 시스템 속성값, 현재 기본 0ms |
완료 대상이 cleaning.stopped인 시작 청정 |
| Security | start/pause/resume/stop 메서드에 맞는 상태 완료 조건 자동 선택 | MainApi 실행기 |
| Mapping | reqmap은 mapping.dataReceived 자동 선택 |
MainApi 실행기 |
| TTS | 완료 조건을 생략하면 재생 요청 반환까지만 처리 | LLM/TTS 실행기 |
| UI 화면 전환 | 완료 조건을 생략하면 화면 적용 증거를 기다리지 않음 | 프레임워크 실행기 |
도메인 기본값은 편의를 위한 임의 추정이 아니라 기존 기능 계약을 안정된 Task 입력으로 바꾸는 어댑터 규칙이어야 한다. 예를 들어 이동 대상 공간, TTS 문장, 화면 이름, 외부 앱 세션 키처럼 의미를 바꾸는 값은 도메인 실행기가 임의 생성하면 안 된다.
청정 기본값 주의: 엄격 검증이 꺼진 상태에서
setAirCleanerOperation에action,mode,speed,operation을 모두 생략하면 실행기가시작·기본 청정·speed=0·ai=false를 보완한다. 기본 청정의 완료 조건은cleaning.stopped이고cleanMinTimeMs기본은 0ms이므로, 시작 직후 정지 명령으로 이어질 수 있다. 이는 하위 호환을 위한 실행기 보완이지 안전한 공개 API 최소 요청이 아니다. 제품 호출자는 최소한 동작과 모드를 명시하고 엄격 검증 시험을 통과해야 한다.
5.4.6 기본값이 없거나 생략하면 안 되는 필드
| 필드·상황 | 생략 결과 | 규범 |
|---|---|---|
제어 method |
raw 경로에서 어느 API인지 판정 불가 | MUST 명시. AAR만 자동 삽입 |
단일 Task taskMethod |
missing_task_method |
MUST 명시 |
Workflow subTasks |
missing_subtasks |
하나 이상의 단계 MUST |
각 Workflow·병렬 자식 taskMethod |
실행 시 missing workflow subTask method 또는 검증 실패 |
각 단계 MUST |
단계 stepId |
단순 순차 실행은 가능하지만 단계 상관관계가 비어 있음 | 의존성·상대 지연·Cloud 추적 단계 MUST |
예약 trigger 또는 시각 필드 |
missing_schedule_trigger |
예약 등록 시 MUST |
| 이동 대상 | 엄격 검증 시 validation_failed, 아니면 실행기에서 unknown_move_target |
공간 ID·이름·좌표 중 지원 값 MUST |
| TTS 문장 | 엄격 검증 시 validation_failed |
tts, text, ttsText, message 중 하나 MUST |
| 화면 전환 대상 | 엄격 검증 시 validation_failed |
screenName, screen, targetScreen 중 하나 MUST |
제품 스케줄 변경의 scheduleId |
엄격 검증 시 validation_failed 또는 하위 기능 실패 |
대상 스케줄을 식별하는 값 MUST |
app.sessionEnded의 completionKey |
missing_completion_key |
앱 패키지·세션 상관 키 MUST |
tts.playbackEnded의 상관 키 |
completionKey → cloud_step_id → requestId → traceId 순으로 찾고 모두 없으면 실패 |
복합 Workflow에서는 명시적 단계 키 SHOULD |
requestId |
Task 실행은 가능하지만 예약 중복 등록 방지 없음 | 외부·예약 요청 SHOULD, 멱등성 요구 시 MUST |
traceId |
Task 실행은 가능하지만 계층 간 추적 연결 없음 | 복합·원격 요청 SHOULD, 추적성 요구 시 MUST |
현재 엄격 검증의 기본값은 false다. 이는 기존 호출 호환성을 위한 선택이지 필수 매개변수가 실제로 선택이라는 뜻이 아니다. 출시 계약에서는 기능 카드에 호출자가 반드시 보내는 값, AAR가 넣는 값, Core 정책값, 도메인 실행기 기본값, 기본값 금지값을 분리해 고정하고, 엄격 검증을 켠 회귀 시험까지 통과해야 한다.
5.5 공통 결과 필드
| 필드 | 의미 |
|---|---|
accepted |
요청 접수 또는 처리 성공 여부 |
taskId / task_id |
TaskManager 내부 task 식별자 |
taskMethod / task_method |
실행 메서드 |
taskQueue / queue |
queue |
taskState / status |
생명주기 상태 |
executionMode |
실행 방식 |
priority |
우선순위 |
source |
요청 출처 |
cancellable |
취소 가능 여부 |
retryCount |
실행 재시도 횟수 |
progress |
0~100 진행률 |
stage |
현재 의미 단계 |
message |
운영/사용자 설명용 메시지 |
workflowName |
상위 Workflow 이름 |
currentStepIndex |
현재 단계 번호 |
currentStepMethod |
현재 단계 메서드 |
subTaskStates |
단계별 상태와 결과 |
taskErrorCode / errorCode |
하위 오류 |
reasonCode / reason_code |
정규화된 실패 사유 |
reasonParams |
대상 등 구조화된 매개변수 |
recoverability |
복구 책임 분류 |
suggestedAction |
다음 권장 동작 |
requiresCloudDecision |
상위 판단 필요 여부 |
result |
기기 도메인 실행기 결과 |
6. 실행 허용 절차
submitTask는 실행기를 호출하기 전에 아래 절차를 통과한다.
6.1 활성화 조건
TaskManager는 다음 중 하나면 활성화된다.
- 요청에
forceTaskManager=true persist.sys.deviceagent.taskmanager.enable=true
해당 속성을 읽지 못했을 때의 기본값은 현재 true다.
6.2 입력 검증
현재 입력 검증은 기존 시스템 호환을 위해 두 단계로 동작한다.
| 모드 | 동작 |
|---|---|
| 기본 | taskMethod 존재 여부만 강제하고, 알려진 메서드의 세부 필드는 엄격하게 검사하지 않음 |
| 엄격 | strictValidation=true이거나 전역 속성이 true이면 메서드별 스키마 검사 |
전역 속성:
persist.sys.deviceagent.taskmanager.strict_validation
예시:
| 메서드 | 엄격한 입력 검증에서 요구하는 값 |
|---|---|
setMoveTo |
positionId, positionName, position, positionIds 중 하나 |
setMoving |
action, operation, moving 중 하나 |
setAirCleanerOperation |
action, mode, speed, operation 중 하나 |
setLlmTts |
tts, text, ttsText, message 중 하나 |
setLauncherScreen |
screenName, screen, targetScreen 중 하나 |
| 스케줄 변경 | 스케줄 ID 또는 메서드별 동작 필드 |
알 수 없는 메서드는 입력 검증기를 통과하더라도 실행기 생성 단계에서 missing_task_command로 거절될 수 있다. 따라서 엄격한 입력 검증만으로 기능 등록 여부까지 보장할 수는 없다.
6.3 호출자 정책
현재 가장 명시적인 요청 출처 정책은 긴급 우선순위 제한이다.
EMERGENCY우선순위는INTERNAL,AUTONOMOUS,SENSOR요청에만 허용한다.bypassCallerPolicy=true는 특권 우회이므로 일반 외부 요청에 노출하면 안 된다.
6.4 도메인 자원 정책
현재 명시적으로 관리하는 충돌 예시는 다음과 같다.
| 요청 | 요구 자원 | 충돌하는 활성 도메인 |
|---|---|---|
rotateInPlace |
movement_base |
Security movement |
observeVisionSemantics |
movement_base, camera |
Security, streaming, vital sign |
| vital sign 화면 | foreground_display, camera, external_app_session |
Security, streaming |
| Security 시작 | camera, movement/session | streaming, vital sign |
requiredResources를 요청에 추가하면 기능별 조건문을 계속 늘리지 않고 자원 요구사항을 구조화할 수 있다. 선택적 상위 Planner도 기능 설명자에 정의된 같은 자원 용어를 사용해야 한다.
6.5 시스템 자원 정책
TaskResourceMonitor는 CPU 사용률, RAM 압력과 발열 단계의 최신 스냅숏을 보관한다. 실행 허용 절차는 resourcePolicyEnabled와 정책 임계값에 따라 작업을 거절할 수 있다. 스냅숏은 하드웨어 상태의 영구 진실이 아니므로 측정 시점과 출처를 함께 확인해야 한다.
6.6 선점 실행 허용
새 요청은 기본적으로 기존 작업을 중단하지 않는다. preemptPolicy가 명시된 경우에만 대기열과 Task 상태를 변경한다.
| 정책 | 동작 |
|---|---|
append |
기존 작업을 유지하고 뒤에 추가 |
clear_pending |
같은 대기열의 PENDING 작업만 취소 |
cancel_running |
같은 대기열에서 실행 중인 작업까지 취소 시도 |
replace_queue |
같은 대기열의 실행 중 작업까지 취소한 뒤 새 요청 제출 |
replace_all |
모든 대기열에서 취소 가능한 Task를 취소한 뒤 제출 |
6.7 기존 DeviceAgent 제품 정책의 계승
TaskManager 도입 전부터 DeviceAgent에는 제품 상태, 배터리, LLM 세션, 개인정보 보호, 오류, 이동 자세와 동작 간 충돌을 판단하는 정책이 있다. TaskManager는 이 정책을 별도 규칙으로 복사하지 않고 승인된 기존 도메인 진입점을 통해 반드시 통과해야 한다.
정책은 다음 네 계층으로 나눈다.
| 계층 | 정책 소유자 | 담당 범위 | TaskManager의 역할 |
|---|---|---|---|
| Task 계약 정책 | TaskBundleValidator, TaskCallerPolicy, TaskPolicyRegistry |
입력, 호출자, 대기열, 우선순위, 시간 제한과 취소 | 실행 전에 공통 계약을 판정한다. |
| 공통 상태·자원 정책 | TaskDomainResourcePolicy, TaskResourcePolicy |
카메라·이동 기반부·전면 앱 세션 충돌, CPU·RAM·발열 | 명백한 공통 충돌을 조기에 차단한다. |
| 제품·도메인 정책 | StateManager, CmdPolicyManager, 도메인별 manager·handler |
제품 모드, LLM, 배터리, AMR 연결, 오류, 개인정보 보호, 현재 동작 간 전환 | 정책 담당자를 우회하지 않고 결과를 구조화된 실패 사유로 변환한다. |
| 물리 부수 정책과 완료 증거 | MovingLocationManager, TiltingManager, LCDManager, 각 domain callback |
이동 자세, 화면 깨움, 정지·도착·도킹·청정 종료 같은 실제 상태 | 내부 자동 동작을 별도 사용자 단계로 만들지 않고 최종 증거를 Task 상태에 반영한다. |
6.7.1 대표 정책 계승 행렬
| 상황 | 기존 정책과 실제 동작 | Task 경로가 지켜야 할 계약 | 소스 기준점 |
|---|---|---|---|
| Factory·ICT·Upgrade·SelfTest | 일반 제품 동작을 제한하거나 별도 모듈로 전달 | 일반 Task 실행 전에 현재 제품 상태를 보존하고 우회하지 않는다. | StateManager.isProductOperationState(), MainApi.executeMethodInternal() |
| Vital Sign·Streaming | 이동·청정·스케줄 등 일부 메서드를 차단 | 화면 전환 성공만으로 후속 이동을 시작하지 않고 세션 상태와 도메인 정책 결과를 확인한다. | StateManager.checkBlockedStatus() |
| LLM 처리 중 | AirSensor 예외 등을 제외한 일반 이동·청정 실행을 제한 | Task 우선순위나 Workflow 순서로 LLM 정책을 덮어쓰지 않는다. | CmdPolicyManager.commonCheck() |
| 저전력·임계 저전력 | 이동·이동청정·스케줄을 제한하고, 저전력 복귀는 별도 우선 정책으로 처리 | 일반 이동과 안전 복귀를 같은 명령으로 취급하지 않는다. | CmdPolicyManager.commonCheck(), isLowBatteryReturnToStationStatus() |
| 개인정보 보호·AMR 미연결·맵 편집·초기화 중 | 이동 계열 동작을 거절 | 도메인 거절을 POLICY_NOT_ALLOWED 계열 실패로 보존한다. |
CmdPolicyManager.commonCheck() |
| 이동 시작 | MOVING 틸트 조건을 켜고 LCD 이벤트를 발생시킨 뒤 AMR 이동 |
Workflow에 tiltDown을 임의로 추가하지 않는다. 이동 도메인이 자세를 자동 관리한다. |
MovingLocationManager.move() |
| 이동 중 일시정지·재개 | 일시정지 시 MOVING=false, 재개 시 MOVING=true |
Task pause·resume이 기존 이동 상태 전이와 틸트 조건을 함께 통과해야 한다. | MovingLocationManager.pause(), resume() |
| 이동 완료·도킹 | 일반 위치 도착 시 MOVING 조건을 해제하고, 스테이션은 충전 증거에서 이동·도킹 조건을 해제 |
위치 도착과 스테이션 충전을 서로 다른 완료 증거로 유지한다. | notifyArrived(), notifyMovingStatus() |
| 이동 중 틸트 | 기본적으로 MOVING 조건은 틸트 DOWN 후보지만 LLM·관찰·보안 등 상위 조건이 최종 자세를 바꿀 수 있음 |
TaskManager가 틸트 결과를 고정하지 않고 TiltingManager의 합성 판단을 따른다. |
TiltingManager.runTiltingChecker() |
| Vision 의미 관찰 | 이동 중이면 거절하고, 정지 후 OBSERVATION 조건으로 틸트 UP 완료를 기다린 뒤 관찰 |
정지 확인 → 관찰 자세 완료 → 최신 Vision 증거 순서를 하나의 도메인 capability 계약으로 유지한다. |
ObservationTaskExecutor.observeVisionSemantics() |
| 청정 중 새 이동 | 관리 이동 실행기는 청정을 정지하고 실제 정지 증거를 기다린 뒤 이동 | 단순 메서드 호출 순서가 아니라 도메인 전환 완료를 확인한다. | MovementTaskExecutor.prepareMovementResource() |
| 복귀 요청 | 기존 동작을 정지하고 높은 우선순위로 복귀하되, 이미 복귀 중이면 기존 상태를 복구·유지 | 일반 선점과 제품 안전 복귀를 구분한다. | CmdPolicyManager.returnToStation() |
이 표의 틸트, LCD 깨움과 도킹 처리처럼 기능 수행에 내재된 제품 정책은 독립 Task로 노출하지 않는다. 독립 Task로 노출하면 Planner나 호출자가 내부 안전 순서를 생략하거나 잘못 재배열할 수 있다. 대신 이동 capability의 실행 계약과 결과에 posturePolicyApplied, physicalCompletionObserved 같은 관측 필드를 추가할 수 있다.
6.7.2 정책 계승 불변 조건
- 관리 실행기는 기존 도메인 정책 담당자를 우회해 HAL·MCU·AMR을 직접 호출하면 안 된다.
- 저수준 호출이 필요한 전용 실행기는 기존 진입점과 동등한 상태·자원 검사를 갖췄다는 별도 검토와 실기기 증거가 있어야 한다.
- TaskManager의
priority,preemptPolicy,forceTaskManager는 제품 안전 정책을 무효화하는 권한이 아니다. - 도메인 정책의 거절·대기·자동 전환 결과는
accepted,errorCode,reason,recoverability로 변환해야 한다. - 암묵적 제품 동작은 Workflow 단계 수를 늘리지 않되, 로그·이벤트·완료 증거에서 적용 여부를 확인할 수 있어야 한다.
- 같은 기능의 기존 경로와 관리 경로는 동일한 정책 조건에서 같은 물리 허용·거절 결과를 내야 한다.
6.7.3 현재 보강이 필요한 경계
| 경계 | 현재 위험 | 보강 기준 |
|---|---|---|
| Legacy 상태 차단 | MainApi의 일부 차단 분기는 구조화된 실패 결과 없이 반환할 수 있음 |
차단 이유를 표준 errorCode와 reason으로 변환한다. |
| 청정 Lock 처리 | Lock 상태에서 실제 실행을 건너뛰면서 성공으로 반환하는 경로가 있음 | skipped와 completed를 분리하고 정책 거절 또는 명시적 no-op 결과로 표현한다. |
| 상태 검사 선택값 | checkBlockedStatus는 Task 입력값에 따라 추가 검사 여부가 달라질 수 있음 |
출시 기능 카드에 필수 상태 검사와 실제 도메인 정책 경로를 고정한다. |
| Security 시험 예외 | 기존 정책 코드에 시험 목적으로 거절이 비활성화된 분기가 존재 | 제품 사양과 시험 예외를 분리하고 출시 형상에서 정책을 확정한다. |
| 저수준 전용 실행기 | 회전·관찰 등 일부 capability는 하위 장치를 직접 사용 | 정지·자원·개인정보 보호·취소·완료 증거의 동등성을 기능별로 입증한다. |
| 정책 변경 추적 | 도메인 정책 변경이 Task 기능 카드와 테스트에 자동 반영되지 않음 | 정책 ID, 소스 기준점, 적용 capability와 회귀 시험을 하나의 추적 항목으로 관리한다. |
7. 실행 정책 목록
TaskPolicyRegistry는 메서드별 기본 실행 정책을 중앙에서 관리한다.
7.1 실행 방식
| 실행 방식 | 의미 | 응답 시점 |
|---|---|---|
DIRECT |
대기열을 거치지 않고 호출 스레드에서 실행 | 실제 메서드 반환 후 |
QUEUED_WAIT |
대기열에 넣고 호출자가 최종 상태까지 대기 | 완료 또는 실패 후 |
ASYNC |
대기열에 넣고 즉시 Task 식별자 반환 | 접수 직후 |
문자열 alias:
direct,sync→DIRECTqueued_wait,wait→QUEUED_WAITasync→ASYNC
7.2 대기열
현재 정책 목록과 런타임에서 사용하는 대기열은 다음과 같다.
| 대기열 | 대표 기능 |
|---|---|
emergency |
stop, reset, emergency 계열 |
movement |
이동, 복귀, 회전 |
cleaning |
청정 실행/정지 |
state |
main/device state, launcher screen |
update |
OTA/firmware 상태 |
sound |
소리·음성 계열 기본 처리 |
settings |
기기 설정 |
ai |
LLM, TTS, Vision 의미 관찰 |
routine |
Eye LED/PUI scene |
schedule |
제품 스케줄 등록·조회·변경·삭제 |
interaction |
Welcome, Wakeup, Relax 등 상호작용 세션 |
security |
WSS Security 세션 |
mapping |
지도와 스테이션 상태 확인 |
device_info |
배터리와 펌웨어 조회 |
workflow |
상위 Workflow 실행 관리 |
default |
명시적 정책이 없는 메서드 |
7.3 우선순위
| 우선순위 | 용도 |
|---|---|
BACKGROUND |
비긴급 유지보수/관찰 |
NORMAL |
일반 실행 |
CONTROL |
일시정지, 재개와 상태 제어 |
HIGH |
이동, 복귀, 중요 세션 제어 |
EMERGENCY |
안전 정지와 복구. 신뢰된 요청 출처로 제한 |
7.4 현재 정책 예시
| 메서드 | 실행 방식 | 대기열 | 우선순위 | 시간 제한 | 취소·보상 동작 |
|---|---|---|---|---|---|
getBatteryInfo |
DIRECT | device_info | NORMAL | 5s | 없음 |
getDeviceStatus |
DIRECT | state | NORMAL | 5s | 없음 |
getStationLocationEvidence |
DIRECT | mapping | NORMAL | 5s | 없음 |
probeDockingSignal |
DIRECT | mapping | NORMAL | 3s | 없음 |
rotateInPlace |
QUEUED_WAIT | movement | HIGH | 30s | stopMovement |
observeVisionSemantics |
QUEUED_WAIT | movement | NORMAL | 10s | stopMovement |
setMainState |
QUEUED_WAIT | state | CONTROL | 30s | 없음 |
setLauncherScreen |
QUEUED_WAIT | state | NORMAL | 30s | 없음 |
setMoveTo |
ASYNC | movement | HIGH | 120s | stopMovement |
returnToStation |
ASYNC | movement | HIGH | 120s | stopMovement |
setAirCleanerOperation |
ASYNC | cleaning | CONTROL | 1200s | 청정 stop 계약 |
setChangeLlmStatus |
ASYNC | ai | HIGH | 30s | LLM stop/status |
| schedule query | DIRECT | schedule | NORMAL | 5s | 없음 |
| schedule mutation | QUEUED_WAIT | schedule | NORMAL | method별 | method별 |
interSchedule |
ASYNC | interaction | HIGH | 1200s | interaction stop |
startSecurityMode |
ASYNC | security | HIGH | 120s | stopSecurityMode |
| security pause/resume | ASYNC | security | CONTROL | 30s | 없음 |
| security stop | ASYNC | security | HIGH | 30s | 없음 |
등록되지 않은 메서드는 이름을 기준으로 실행 방식과 대기열을 추정한다. 이 기본 처리는 기존 기능을 수용하기 위한 임시 안전망일 뿐, 출시 가능한 기능 등록을 뜻하지 않는다. 제품 출시 대상 기능에는 명시적 정책과 실행기를 등록해야 한다.
제3부 · 실행 생명주기와 Workflow — 8~15장은 Task 상태, 실행 방식, 단계 제어, 완료 증거, 취소, 실패와 예약을 정의한다.
8. TaskRecord와 생명주기
8.1 TaskRecord가 보존하는 정보
| 구분 | 필드 |
|---|---|
| 식별 | taskId, method, workflowName |
| 입력 | input, source, 요청·추적·상관관계 메타데이터 |
| 실행 | queueKey, executionMode, priority, timeoutMs |
| 정책 | maxRetries, cancellable, cancelMethod |
| 상태 | state, progress, stage, message |
| 시간 | createdAtMs, startedAtMs, finishedAtMs, updatedAtMs |
| 실패 | errorCode, reason, reasonCode, reasonParams |
| 복구 | recoverability, suggestedAction, requiresCloudDecision |
| Workflow | currentStepIndex, currentStepMethod, workflowStepStates |
| 상위·하위 관계 | parentRecord, parentGroupId, activeChildRecords |
| 생명주기 | 취소·보상 동작 명령과 실행·실패 여부 |
| 결과 | result, workflowState |
8.2 상태 모델
| 상태 | 의미 | 최종 상태 여부 |
|---|---|---|
PENDING |
대기열에서 실행 대기 | 아니오 |
RUNNING |
실행기 또는 Workflow 실행 중 | 아니오 |
CANCELLING |
취소 명령과 실행 중단 여부 확인 중 | 아니오 |
COMPLETED |
성공을 증명하는 실제 완료 증거까지 확인 | 예 |
FAILED |
실행 오류, 시간 초과, 예약 시점의 실행 불가 또는 취소 확인 실패 | 예 |
PARTIAL_FAILED |
병렬 일부 실패를 보존 | 예 |
CANCELLED |
취소가 확인됨 | 예 |
CANCELLED는 COMPLETED가 아니다. PUI에서 사용자가 청정을 중단하거나 앱 세션을 취소한 경우에도 “작업 종료”와 “목표 성공”을 구분해야 한다.
8.3 ID와 보존
- Task ID는 런타임 순번을 바탕으로 생성된다.
- 스케줄 ID는 별도 순번을 사용한다.
- 메모리 내 실행 기록은 최근
100건으로 제한된다. - Task 기록과 예약 기록의 영속성은 서로 다른 속성과 파일을 사용한다.
- 저장소에서 복원한 상태는 실제 하드웨어 상태와 다를 수 있으므로, 부팅 후 최신 상태와 대조해 정합해야 한다.
8.4 진행률
updateTaskProgress는 진행률을 0~100 범위로 제한한다.stage는 의미 단계,message는 운영 설명을 담는다.- 병렬 하위 Task의 진행률은 상위 Task의 평균 진행률로 집계한다.
- 상위 Workflow는 현재 단계 번호·메서드와 단계별 상태 목록을 함께 제공한다.
- 진행률은 완료 증거를 대체하지 않는다. 100% 값만으로
COMPLETED를 만들면 안 된다.
9. 실행 런타임
9.1 DIRECT
- 실행 기록 생성 및 저장
RUNNING상태와STARTED이벤트 기록- 호출 스레드에서 명령 실행
- 결과 저장
- 성공 시
COMPLETED, 예외 시FAILED - 최종 상태 지표와 이벤트 기록
DIRECT는 짧은 조회에 적합하다. 물리 동작처럼 메서드 반환과 실제 완료 시점이 다른 기능에 사용하면 안 된다.
9.2 QUEUED_WAIT
- 우선순위가 지정된 작업을 대기열에 제출
- 호출자는
Future.get(timeout)으로 대기 - 런타임이 재시도, 완료 대기와 최종 상태 관리
- 시간 초과 또는 중단 발생 시 구조화된 실패 반환
- 최종 결과를 호출자에게 반환
호출 스레드를 점유하므로 긴 사용자 세션에는 신중하게 사용한다.
9.3 ASYNC
- 대기열에 Task 제출
accepted=true,taskId를 즉시 반환- 실제 실행과 완료 증거 대기는 실행기 스레드에서 계속됨
- 진행·완료·실패는 이벤트와 상태 조회로 관찰
이동, 복귀, 청정, 보안처럼 시간이 걸리는 동작의 기본 실행 방식이다.
9.4 재시도
maxRetries는 실행 정책 또는 요청의retry로 결정한다.- 실행 예외가 발생하면 재시도 횟수를 증가시키고, 상한에 도달할 때까지 같은 관리 대상 명령을 다시 실행한다.
- 기기 동작이 이미 일부 수행됐을 수 있으므로 재시도 가능한 메서드는 멱등성을 보장해야 한다.
- 물리 이동과 청정은 무조건 다시 호출하지 말고 현재 상태와 실패 사유를 확인해야 한다.
10. Workflow 런타임
10.1 상위 Workflow와 단계
submitWorkflow는 하나의 상위 TaskRecord를 만들고 subTasks를 순서대로 처리한다.
각 순차 단계는 다음 정보를 가진다.
| 단계 상태 필드 | 의미 |
|---|---|
index |
Workflow 안의 단계 순번 |
stepId, cloud_step_id |
기기 단계와 상위 계획 단계의 식별자 |
taskMethod |
단계에서 실행하는 기기 기능 |
state |
단계의 현재 생명주기 상태 |
stage, message |
진행 구간과 운영·사용자 표시 문구 |
completedAtMs |
단계가 종료된 시각 |
result |
단계 실행 결과 |
errorCode, reason |
단계 실패 코드와 원인 |
10.2 순차 실행
각 단계의 기본 순서는 다음과 같다.
- 별칭 정규화와 입력 검증
- 도메인 자원 실행 허용 판정
- 단계 상태를
PENDING으로 변경 - 시작 조건과 실행 조건 평가
WORKFLOW_STEP_STARTED- 도메인 명령 생성과 실행
- 완료 조건 대기
- 결과 저장 후
COMPLETED로 변경 WORKFLOW_STEP_COMPLETED- 다음 단계 진입
앞 단계의 실제 완료 증거가 없으면 다음 단계를 시작하면 안 된다.
10.3 단계 의존성
현재 구현은 두 가지 실행 조건을 지원한다.
| 조건 유형 | 의미 | 조건 불충족 처리 |
|---|---|---|
step_completed |
지정 단계가 COMPLETED 또는 SKIPPED인지 확인 |
실패 |
step_output_equals |
지정 단계 결과의 Bundle 경로가 기대값과 같은지 확인 | onFalse=skip 또는 실패 |
예시:
{
"stepId": "clean-if-available",
"taskMethod": "setAirCleanerOperation",
"conditions": [
{
"type": "step_output_equals",
"stepId": "read-air-quality",
"path": "result.needs_cleaning",
"value": "true",
"onFalse": "skip"
}
]
}
step_output_equals는 현재 Boolean 또는 String 비교를 지원한다. 범위 비교, 숫자 연산자와 복합 AND/OR 조건식은 목표 확장이다.
10.4 이전 단계 기준 지연
after_step 시작 조건은 선행 단계 완료 후 일정 시간이 지나면 다음 단계를 시작한다.
{
"stepId": "vital-after-move",
"taskMethod": "setLauncherScreen",
"screenName": "vitalSign",
"trigger": {
"type": "after_step",
"stepId": "move-room-1",
"delayMs": 30000
},
"conditions": [
{
"type": "step_completed",
"stepId": "move-room-1"
}
]
}
지연 시간 동안 단계 상태는 WAITING, 세부 단계는 scheduled_delay_wait가 되며 remainingDelayMs가 갱신된다. 현재 구현은 Workflow 스레드 안에서 대기하므로, 매우 긴 지연은 별도의 영속 예약 실행으로 처리해야 한다.
10.5 병렬 그룹
{
"type": "parallelGroup",
"groupId": "feedback-group",
"joinPolicy": "all_success",
"failurePolicy": "partial_success",
"tasks": [
{"taskMethod": "setEyeLedColor", "color": "calm"},
{"taskMethod": "setLlmTts", "text": "청정을 시작합니다"}
]
}
현재 구현은 다음과 같다.
- 각 하위 Task에 별도
TaskRecord를 만든다. - 각 하위 Task를 정책에 지정된 대기열에 동시에 제출한다.
- 상위 Task는 각 하위 Task의 실행 결과를 기다린 뒤 하나의 그룹 결과로 취합한다.
- 그룹 시간 제한은 하위 Task 시간 제한 중 가장 큰 값으로 계산한다.
- 상위 Workflow의 시간 제한은 순차 단계 제한 시간의 합과 병렬 그룹별 최대 제한 시간을 합산한다.
joinPolicy값은 상태에 보존하지만, 현재 런타임은 모든 하위 Task가 끝날 때까지 기다린다.
10.6 실패 정책
| 실패 정책 | 현재 동작 |
|---|---|
fail_parent |
하위 Task 실패를 상위 Task 실패로 전파 |
partial_success |
그룹과 상위 Task를 PARTIAL_FAILED로 보존 |
continue_on_failure |
실패 정보를 남기고 다음 단계 진행 가능 |
partial_success를 전체 성공으로 처리하면 안 된다. 상위 서비스와 UX는 “일부 완료” 상태를 명시적으로 다뤄야 한다.
10.7 Workflow 대기열의 책임 경계
- 상위 Task는
workflow대기열을 사용한다. - 하위 Task는 메서드 정책에 지정된 도메인 대기열을 사용한다.
- 상위 Task를 취소할 때는 실행 중인 하위 Task의 취소 명령과 비동기 실행도 함께 정리한다.
- 상위 Task만 취소되고 실제 기기 동작이 계속되는 상태를 허용하면 안 된다.
11. 완료 증거
11.1 왜 메서드 반환만으로 부족한가
setMoveTo()가 성공을 반환해도 이동 요청이 전달됐다는 뜻일 뿐, 목표 공간 도착을 보장하지 않는다. setLauncherScreen()도 화면 전환 요청과 사용자의 측정 완료는 서로 다른 사건이다.
TaskManager는 다음 세 시점을 분리한다.
| 이벤트 단계 | 의미 |
|---|---|
accepted |
요청을 접수하고 실행 관리가 시작됨 |
started |
기기 도메인의 실제 실행이 시작됨 |
completed |
목표를 증명하는 실제 완료 증거를 확인함 |
11.2 현재 완료 조건
| 도메인 | 완료 조건 | 완료 의미 |
|---|---|---|
| Movement | movement.arrived |
목표 공간 도착 |
| Movement | movement.stationCharging |
스테이션 복귀 후 충전 상태 |
| Movement | movement.rotationCompleted |
제자리 회전 완료 |
| Cleaning | cleaning.started |
청정 시작 확인 |
| Cleaning | cleaning.stopped |
청정 동작의 최종 중지 확인 |
| Cleaning | cleaning.stepComplete |
청정 내부 단계 완료 |
| Cleaning | cleaning.reportDone |
청정 결과 보고 완료 |
| Interaction | interaction.started |
상호작용 세션 시작 |
| Interaction | interaction.arrived |
상호작용 위치 도착 |
| Interaction | interaction.actionStarted |
콘텐츠/동작 시작 |
| Interaction | interaction.actionEnded |
콘텐츠/동작 종료 |
| Interaction | interaction.returning |
복귀 시작 |
| Interaction | interaction.completed |
전체 상호작용 완료 |
| Security | security.started |
보안 모드 시작 |
| Security | security.paused |
보안 일시정지 |
| Security | security.resumed |
보안 재개 |
| Security | security.stopped |
보안 모드 종료 |
| Security | security.patrolCompleted |
순찰 주기 완료 |
| Mapping | mapping.dataReceived |
지도 데이터 수신 |
| App | app.sessionStarted |
외부 앱 세션 시작 |
| App | app.sessionEnded |
사용자 완료/정상 종료 |
| TTS | tts.playbackStarted |
실제 재생 시작 |
| TTS | tts.playbackEnded |
실제 재생 종료 |
| UI | ui.screenApplied |
화면 적용 확인 |
현재 DeviceAgent Core의 완료 조건 목록과 AAR 공개 상수 목록은 완전히 같지 않다.
Core에는 movement.rotationCompleted, tts.playbackStarted,
tts.playbackEnded, ui.screenApplied가 있지만 현재
TaskManagerClient.TaskCompletionTargets에는 이 네 상수가 없다. 원시 문자열로는
요청할 수는 있지만 타입 기반 SDK 계약이 완성된 것은 아니다. AAR 상수 추가와
계층 간 상수 정합성 검사가 필요하다.
11.3 CompletionStateStore
- 완료 조건과 선택적 공간 ID를 기준으로 최신 완료 이벤트를 저장한다.
- 완료 조건의 전역 키와 공간별 키를 함께 기록한다.
observedAtMs가 task의completionSinceMs보다 최신이어야 한다.completionStableMs동안 상태가 유지돼야 안정적인 완료 증거로 인정한다.- 중단 이벤트는 성공 이벤트와 별도 저장소에 기록한다.
- 완료 이벤트는 의미 관찰 기록에도 남긴다.
11.4 CompletionWatcher
이 since 기준이 없으면 이전 이동이나 TTS 이벤트가 새 Task를 즉시 완료시키는 과거 증거 재사용 문제가 생긴다.
11.5 장기 세션 완료 의미
| 기능 | 시작 증거 | 정상 완료 | 취소·실패 |
|---|---|---|---|
| Vital Sign | 앱 세션 실행 중 | 사용자가 측정을 완료하고 앱이 최종 결과 반환 | 사용자 취소 또는 앱 오류 |
| Security | 보안 모드 시작 | 사용자가 모드를 종료하거나 정책상 최종 이벤트 발생 | 중지·취소·실패 |
| Welcome | 상호작용 시작 또는 위치 도착 | 예약된 시나리오의 동작과 복귀까지 완료 | 사용자 취소, 시간 초과, 도메인 실패 |
| TTS | 재생 시작 | 재생 후 LLM 상태가 IDLE로 전환 | 호출어 취소 또는 STOP |
| Launcher 화면 | 화면 적용 | 단순 전환은 적용 확인. 앱 세션이면 세션 종료까지 확인 | 앱 취소 또는 오류 |
화면이 열렸다는 이유로 Vital Sign 측정 Task 전체를 완료하면 안 된다. 이 경우 setLauncherScreen은 시작 단계이고 app.sessionEnded가 완료 단계다.
11.6 AppSessionCompletionBridge
- 패키지가
running이면app.sessionStarted를 기록한다. - 현재 활성 패키지의 최종 이벤트만 수용한다.
- 취소 결과는
app.sessionEnded중단으로 기록한다. - 실패 결과는 실패 사유를 중단 증거로 기록한다.
- 그 밖의 최종 결과는 성공
app.sessionEnded로 기록한다.
11.7 LlmTaskCompletionBridge
- TTS Task마다
completionKey가 필요하다. - 동시에 하나의 재생만 활성화할 수 있다.
- 처리 중 또는 재생 중 상태에서 시작 증거를 기록한다.
- 시작 뒤 상태가 IDLE이 되면 재생 종료를 기록한다.
- 호출어 취소와 STOP은 중단 증거다.
12. 취소와 보상 동작
12.1 취소 처리 순서
- 대상 실행 기록과 최종 상태 여부 확인
cancellable확인CANCELLING전이- 실행 중인 Workflow 하위 Task 취소
- 실행 중이면 취소 명령 실행
- 비동기 실행 취소와 대기열 제거
- 취소 증거가 충분하면
CANCELLED - 취소 확인이 불충분하면
FAILED(cancel_failed)
12.2 확인된 생명주기 계약
| 도메인 | 취소 메서드 | 보강 매개변수 |
|---|---|---|
| Movement | stopMovement |
생명주기 동작과 대상 메서드 |
| Cleaning | setAirCleanerOperation |
action=0, 모듈·TaskManager 메타데이터 |
| LLM | setChangeLlmStatus |
중지 상태 |
| Interaction | interSchedule |
action=0 |
| Security | stopSecurityMode |
도메인 중지 계약 |
12.3 보상 동작
보상 동작은 취소와 다르다.
- 취소는 현재 실행을 멈춘다.
- 보상 동작은 이미 발생한 기기 변화를 안전한 상태로 되돌린다.
예를 들어 이동 후 화면 전환에 실패한 Workflow에서 “원위치 복귀”가 항상 올바른 보상 동작은 아니다. 배터리와 장애 상태에 따라 스테이션 복귀나 현 위치 대기가 더 안전할 수 있다. 따라서 보상 메서드는 기능별 안전성 검토를 거쳐 등록한다.
12.4 PUI 취소
PUI 버튼이 기기 도메인을 직접 중단한 경우에도 TaskManager가 최종 상태 증거를 받아야 한다.
PUI와 음성 경로가 별도 상태를 관리하면 실제 기기는 멈췄는데 TaskManager에는 계속 RUNNING으로 남는 고립 Task가 생긴다.
13. 실패 사유 계약
실패를 자연어 한 문장으로만 전달하면 상위 시스템이 안전하게 분기할 수 없다. TaskManager는 하위 오류와 제품 수준의 실패 사유를 분리한다.
13.1 실패 사유 코드
| 실패 사유 코드 | 대표 하위 오류 | 의미 |
|---|---|---|
TIMEOUT |
timeout, completion_timeout | 제한 시간 내 완료 증거 없음 |
INTERRUPTED |
interrupted | 실행 스레드 중단 |
USER_CANCELLED |
cancelled | 사용자 또는 명시적 취소 |
DEVICE_BUSY |
queue_full, resource_busy | 현재 실행 충돌 |
RESOURCE_LIMIT |
cpu/ram/thermal limit | 시스템 자원 부족 |
STATE_CONDITION_FAILED |
move policy not allowed 등 | 현재 기기 상태에서 실행 불가 |
CAPABILITY_UNAVAILABLE |
validation/missing command | 기능 또는 입력 계약 없음 |
PATH_BLOCKED |
navigation path blocked | 이동 경로 장애 |
ROOM_NOT_FOUND |
position/location not found | 대상 공간을 기기 공간 정보와 연결하지 못함 |
LOW_BATTERY |
battery low | 전력 조건 미충족 |
SENSOR_ERROR |
sensor failure | 필요한 관찰 실패 |
UNKNOWN |
정규화되지 않은 오류 | 분류되지 않은 실패 |
13.2 실패 사유 매개변수
현재 공통 매개변수는 다음을 보존한다.
task_methodtarget_location_idtarget_location_nametarget_position
13.3 복구 가능성과 후속 조치
| 실패 사유 | 복구 가능성 | 권장 조치 |
|---|---|---|
| LOW_BATTERY | device_self_recoverable |
DOCK_AND_RESUME |
| PATH_BLOCKED | user_action_required |
ASK_USER_CLEAR_PATH |
| ROOM_NOT_FOUND | user_action_required |
ASK_USER_TARGET |
| USER_CANCELLED | user_action_required |
CANCEL_WORKFLOW |
| DEVICE_BUSY/RESOURCE_LIMIT/TIMEOUT | auto_retryable |
RETRY_OR_WAIT |
| STATE/CAPABILITY/SENSOR | cloud_replan_required |
REPLAN |
| 기타 | cloud_replan_required |
ASK_USER |
13.4 Cloud 판단 경계
현재 requiresCloudDecision은 실패 사유에 따라 계산된다. 다만 이 값이 true라고 해서 반드시 LLM을 호출해야 하는 것은 아니다.
20.5 콜백 이후 재계획 경계의 구조도처럼 짧은 대기 후 재시도, 저전력 복귀와 명시적 취소 종료는 기기 내부 정책으로 처리할 수 있다. 목표 공간 대체, 기능 변경, Workflow 재구성이나 사용자 동의가 필요하면 상위 판단으로 전달한다.
14. 이벤트 계약
14.1 이벤트 종류
| 이벤트 이름 | 의미 |
|---|---|
STARTED |
Task 시작 |
PROGRESS |
진행률/단계 갱신 |
COMPLETED |
Task 성공 완료 |
FAILED |
Task 실패 |
CANCELLED |
Task 취소 완료 |
WORKFLOW_STEP_WAITING |
선행 단계 기준 지연 또는 조건 대기 |
WORKFLOW_STEP_STARTED |
Workflow 단계 시작 |
WORKFLOW_STEP_COMPLETED |
Workflow 단계 종료 |
WORKFLOW_STEP_SKIPPED |
조건 불충족으로 단계 생략 |
예약 BLOCKED |
실행 시점의 허용 판정에서 차단됨 |
14.2 이벤트 데이터
{
"type": "task_event",
"deviceId": "A1-board-005",
"eventName": "WORKFLOW_STEP_COMPLETED",
"taskId": "task-42",
"taskMethod": "setMoveTo",
"source": "CLOUD",
"state": "RUNNING",
"queue": "workflow",
"progress": 33,
"traceId": "trace-001",
"workflowName": "room_clean_return",
"currentStepIndex": 0,
"currentStepMethod": "setMoveTo",
"cloud_workflow_id": "wf-001",
"cloud_step_id": "move-bedroom",
"stage": "movement",
"message": "안방 이동 완료",
"completionTarget": "movement.arrived",
"requires_cloud_decision": false,
"ts": 1786400000000
}
14.3 이벤트 처리 원칙
- 정상 진행·완료 이벤트는 기기 내부 상태와 UI 갱신에 사용한다.
- 모든 이벤트마다 Planner를 다시 호출하지 않는다.
- 실패 이벤트도 기기 내부에서 복구할 수 있는 사유인지 먼저 확인한다.
- Cloud Workflow와 단계의 상관관계 필드를 보존한다.
- 콜백 수신자는 중복 이벤트를 견딜 수 있어야 한다.
- 최종 이벤트 이후 도착한 과거 진행 이벤트는 무시해야 한다.
15. 예약 실행
TaskManager의 예약 실행은 제품의 반복 스케줄 기능과 구분해야 한다.
15.1 세 시간 계층
| 계층 | 예시 | 소유자 | 저장/실행 |
|---|---|---|---|
| 제품 반복 일정 | 매일 밤 9시 청정 | Schedule 도메인 | 제품 스케줄 DB와 정책 |
| TaskManager 지연 실행 | 30분 뒤 안방 청정 | TaskManager | ScheduledTaskRecord와 실행 시점 허용 판정 |
| 선행 단계 기준 지연 | 이동 완료 30초 후 화면 전환 | Workflow 런타임 | after_step + delayMs |
15.2 예약 등록과 실행 분리
scheduleTask와 scheduleWorkflow는 등록 시점에 기기 기능을 실행하지 않는다.
15.3 예약 유형
| 유형 | 의미 | 현재 Core 처리 |
|---|---|---|
deferred_task |
TaskManager 일회성 지연 실행 | 지원 |
native_product |
제품 고유 반복 스케줄 | AAR 상수는 있으나 TaskManager 지연 등록과 구분 |
event_continuation |
이벤트 콜백 기반 재개 | 계약 확장 값으로, 일반 지연 등록과 분리 |
현재 TaskManager.normalizeDeferredScheduleKind()는 Core 예약 등록을 deferred_task로 제한한다. 제품 스케줄은 기존 스케줄 메서드를 Task로 호출할 수 있지만, 일정 데이터의 저장과 관리 책임은 제품 Schedule 도메인에 남는다.
15.4 실행 조건과 미실행 처리
예약 요청은 절대 시각 또는 상대 지연 시간을 정규화해 실행 시각을 저장한다. 주요 필드는 다음과 같다.
triggertriggerAtMsrelativeDelayMsmissedRunGraceMs/missed_run_grace_msrequireFreshDeviceContextblockWhenTaskManagerBusy
실행 시각이 허용 유예 시간을 지난 Task는 MISSED_RUN_EXPIRED로 차단할 수 있다. 오래된 예약을 뒤늦게 무조건 실행하면 이동이나 청정이 예상하지 않은 시간에 시작될 수 있다.
15.5 예약 상태
| 상태 | 의미 |
|---|---|
SCHEDULED |
등록됐고 실행 시각 전 |
ADMITTED |
실행 시각에 실제 Task 또는 Workflow 제출 성공 |
BLOCKED |
실행 시각이 됐지만 현재 상태에서 실행 불가 |
CANCELLED |
실행 전 예약 취소 |
15.6 영속성
기본 예약 저장소:
/mnt/data2/db/taskmanager_scheduled_tasks.json
관련 시스템 속성:
persist.sys.deviceagent.taskmanager.schedule_persist
persist.sys.deviceagent.taskmanager.schedule_persist_path
등록 후 스냅숏을 저장하고 AlarmManager 실행기가 다음 실행 시각을 재예약한다. 부팅 복원 후에는 기기 식별자, 시계 변경과 미실행 유예 시간을 다시 검증해야 한다.
예약 런타임이 코드에 존재한다고 자동 실행되는 것은 아니다. 현재 기본값은 다음과 같다.
| 설정 | 기본값 | 의미 |
|---|---|---|
taskmanager.scheduler.enable |
false | 30초 주기 실행 시각 확인 비활성 |
taskmanager.scheduler.interval_ms |
30000 | 실행 시각 확인 주기 |
taskmanager.scheduler.limit |
20 | 한 번에 실행 허용할 최대 예약 수 |
taskmanager.scheduler.exact_alarm |
false | setExactAndAllowWhileIdle 재예약 비활성 |
따라서 출시 형상에서 예약 자동 실행을 보장하려면 등록 성공뿐 아니라 해당 속성, 수신기·서비스 생명주기, 정확한 알람 권한, 재부팅 복원과 실행 시각 이벤트를 함께 확인해야 한다.
15.7 현재 검증 경계
- API 등록, 조회, 취소, 영속 저장과 수동 실행 허용 경로는 구현돼 있다.
- 실기기에서 일부 스케줄 등록, 복원과 실행 시각 검증 기록이 있다.
- 모든 제품 모드와 복합 Workflow의 정확한 알람 자동 실행은 기기·APK 조합별 출시 인수 시험이 필요하다.
- “코드가 있다”와 “장시간, 재부팅, 네트워크, 시계 변경 시나리오를 통과했다”를 구분한다.
제4부 · 도메인과 외부 연동 — 16~20장은 기존 기기 기능, 계획 컨텍스트, AAR, IoT/MQTT와 선택적 Planner 연결을 설명한다.
16. 도메인 기능과 실행기 연결
16.1 실행기 등록 원칙
TaskExecutorBootstrap은 표준 taskMethod를 도메인 어댑터에 등록한다.
실행 연결은 SKIX 제품 앱에서 기기 도메인까지의 호출 계층에 표시한 것처럼 taskMethod를 TaskExecutorRegistry, 도메인별 TaskExecutor, 기존 DeviceAgent manager·controller·API 순서로 전달한다.
실행기 어댑터가 해야 할 일:
- Task 계약 필드를 도메인 입력으로 정규화한다.
- 기존 도메인 기능을 호출한다.
- 요청 전달 결과를
outdata에 기록한다. - 비동기 기능이면 완료 연결부가 사용할 상관관계 키를 등록한다.
- 실제 완료는 도메인 콜백을 통해
TaskCompletionStateStore에 기록한다.
실행기 어댑터가 하면 안 되는 일:
- 자연어 원문이나 채널별 요청 문자열을 다시 파싱한다.
- 임의의 기본값으로 잘못된 공간이나 모드를 추정한다.
- 콜백 없이 고정 대기 시간만으로 물리 완료를 선언한다.
- 동일 기능의 핵심 로직을 복제한다.
- 등록되지 않은 메서드를 리플렉션으로 무제한 실행한다.
16.2 현재 실행기 그룹
| 실행기 | 대표 메서드 | 실제 수행 주체 |
|---|---|---|
FrameworkTaskExecutor |
battery, firmware, main/device status, screen, configuration | DeviceAgent framework state |
StationLocationTaskExecutor |
스테이션 위치 증거 조회 | 스테이션·맵 제공자 |
DockingSignalProbeTaskExecutor |
도킹 신호 관찰 | AMR·충전 상태 증거 |
ObservationTaskExecutor |
rotate, vision semantics | movement + Vision AI |
MainApiTaskExecutor |
map, security, follow state, 기타 MainApi 기능 | 기존 MainApi/domain |
MovementTaskExecutor |
move, return, stop | MovingController/AMR |
CleaningAmpTaskExecutor |
cleaning start/stop/status | Cleaning/Amp domain |
LlmTtsTaskExecutor |
LLM status, TTS, stop | LlmManager |
IotTaskExecutor |
device status, config | IotAgent path |
RoutineTaskExecutor |
Eye LED scene | Routine/PUI domain |
ScheduleTaskExecutor |
product schedule CRUD, interaction | Schedule domain |
UpdateTaskExecutor |
OTA/firmware state | Update domain |
16.3 공개 메서드 목록
기기 정보와 상태
| method | 분류 | 비고 |
|---|---|---|
getBatteryInfo |
query | planning context에도 포함 |
getFirmwareVersion |
query | device version |
getMainState |
query | current mode |
getDeviceStatus |
query | device status |
getConfiguration |
query | configuration snapshot |
setMainState |
control | main state 전환 |
setDeviceStatus |
control | device status 반영 |
setLauncherScreen |
control/session start | screenName canonical |
이동과 지도
| method | 분류 | completion 후보 |
|---|---|---|
setMoveTo |
long-running | movement.arrived |
returnToStation |
long-running | movement.stationCharging |
setMoving |
control | operation별 별도 완료 증거 필요 |
stopMovement |
cancel/control | 이동 최종 상태 확인 |
getFollowMeStatus |
query | follow state |
reqmap |
long-running/query mix | mapping.dataReceived |
isMapFilePresent |
query | map readiness |
resetReturnToStationCounter |
control | post-check 권장 |
setAMRMonitoring |
control | monitoring 상태 확인 |
getStationLocationEvidence |
query | 스테이션 위치 증거 스냅숏 |
probeDockingSignal |
observation | current signal only |
rotateInPlace |
bounded action | movement.rotationCompleted |
observeVisionSemantics |
observation | semantic result |
청정
| method | 분류 | 비고 |
|---|---|---|
getAirCleanerOperation |
query | running/paused/current mode |
setAirCleanerOperation |
long-running/control | action/mode/speed |
setStatusClean |
state update | domain status |
startSimpleAirClear |
alias/capability | canonical cleaning으로 정규화 필요 |
startBasicAirClear |
alias/capability | basic mode |
startFixedAirClear |
alias/capability | fixed cleaning |
startAllAirClear |
alias/capability | all-room cleaning |
startSelectiveAirClear |
alias/capability | selected rooms |
startAirSensorAirClear |
alias/capability | sensor-based mode |
stopAirClear |
control | 정지 증거 |
pauseAirClear |
control | paused state |
resumeAirClear |
control | resumed state |
returnAirClearToStation |
compound alias | cleaning stop/return 경계 확인 |
returnCleaningToStation |
compound alias | alias 정합 필요 |
stopCleaning / ampStop |
low-level control | executor 등록 상태 확인 |
LLM, TTS, UI와 루틴
| method | 분류 | completion |
|---|---|---|
setChangeLlmStatus |
state control | LLM 상태 콜백 |
setLlmTts |
long-running playback | tts.playbackEnded |
stopLlm |
cancel | 정지·유휴 증거 |
stopTts |
cancel | aborted playback |
setEyeLedColor |
bounded setting | post-check 또는 ACK |
setCurrentPuiEyeLedColor |
bounded setting | post-check 또는 ACK |
startEyeLedScene |
bounded routine | scene-specific lifecycle 필요 |
설정
| method | 분류 |
|---|---|
setConfig |
mutation |
getConfig |
query |
getAirClearAutoStartModeEnable |
query |
제품 스케줄과 상호작용
| method | 역할 |
|---|---|
addSchedule, editSchedule, deleteSchedule |
제품 schedule CRUD |
scheduleiot, setActiveSchedule, puiEditSchedule |
IoT/PUI schedule mutation |
callschedule, getschedule, getUpComingSchedule |
실행/조회 |
setScheduleExecuted |
execution state update |
| holiday methods | 휴일 예외 정책 |
gpsLocNearBy |
위치 기반 schedule trigger 지원 |
interSchedule |
welcome/wakeup/relax 등 interaction session |
보안
| method | 역할 | 완료 기준 |
|---|---|---|
checkSecurityBasicAvailability |
실행 가능성 query | 즉시 result |
startSecurityMode |
장기 session 시작 | security.started |
pauseSecurityMode |
session pause | security.paused |
resumeSecurityMode |
session resume | security.resumed |
stopSecurityMode |
session 종료 | security.stopped |
업데이트
| method | 역할 |
|---|---|
OTAUpdateArmResult |
ARM update result 처리 |
OTAUpdateMcuResult |
MCU update result 처리 |
setFirmwareUpdateStatus |
firmware update state 반영 |
16.4 기능 등록 체크리스트
새 DeviceAgent 기능을 TaskManager에 연결할 때 다음을 모두 정의한다.
- 표준
taskMethod - 조회·제어·장기 실행 분류
- 입력 스키마와 별칭
- 요청 출처 허용 범위
- 실행 방식
- 대기열과 우선순위
- 시간 제한, 재시도와 멱등성
- 필수 자원
- 실행기 어댑터
- 시작·완료·중단 증거
- 취소 메서드
- 보상 동작 필요 여부
- 실패 사유 변환
- 계획 컨텍스트에 노출할 상태
- 단위·통합·실기기 인수 시험
17. 기기 계획 컨텍스트
getDevicePlanningContext는 기능 정의가 아니라 현재 기기 상태의 스냅숏이다.
17.1 컨텍스트 구조
{
"schema_version": "device_context.v1",
"snapshot_ts": 1786400000000,
"updated_at_ms": 1786400000000,
"main_state": "...",
"battery": {},
"map": {},
"location": {},
"station": {},
"air_quality": {},
"cleaning": {},
"movement": {},
"network": {},
"voice_llm": {},
"security": {},
"interactions": {},
"task_manager": {},
"semantic_observations": {},
"capabilities": {}
}
17.2 컨텍스트 도메인
| 도메인 | 주요 필드 | 주의점 |
|---|---|---|
| battery | percent, is_low, is_charging, freshness | 오래된 정보이면 판단에 사용하지 않음 |
| map | rooms, room_count, editing, source | 지도 편집 중에는 사용 불가 |
| location | current_room_id/name, x/y/theta, is_on_station | 내부 ID를 사용자에게 그대로 안내하지 않음 |
| station | 위치 증거, docking/charging | 지도상 스테이션과 실제 도킹 상태 분리 |
| air_quality | PM, TVOC, NOx, HCHO, CO2, 온습도, AQ level | 원시 필드 이름을 그대로 TTS하지 않음 |
| cleaning | is_running, is_paused, last_action, area_info | 현재 Task와 교차 확인 |
| movement | moving_status, is_moving, is_paused, blocked | 목표 위치와 현재 위치 분리 |
| network | AWS IoT connected, freshness | 구독 준비와 실제 연결 상태 분리 |
| voice_llm | pipeline state, busy, session, output, model readiness | 음성 세션 중 TaskManager 일시정지 정책과 연결 |
| security | session, stage, current area, low light | 장기 세션의 생명주기 관리 필요 |
| interactions | 등록된 제품 스케줄 요약 | TaskManager 지연 Task와 구분 |
| task_manager | 대기열, 실행 중·최근·예약 Task | 실행 계획과 현재 상태 설명 |
| semantic_observations | 최근 관찰 증거와 최신성·개인정보 상태 | 제한된 관찰 결과만 사용 |
| capabilities | 이동, 청정, 복귀, TTS 등 | 실제 실행기·정책 목록과의 불일치 점검 |
17.3 공간 정보 계약
각 room은 최소 다음을 제공한다.
{
"id": "5",
"name": "안방",
"x": "...",
"y": "...",
"theta": "...",
"station": false
}
상위 호출자는 공간 이름을 areaId와 연결한 뒤 Workflow를 만든다. TaskManager는 존재하지 않는 공간을 임의로 대체하면 안 된다.
17.4 정보 최신성
컨텍스트 출처는 다음 메타데이터를 가질 수 있다.
observed_at_msfreshness_msttl_mssource_validstaleusablesource_stateexpiry_mode
조건부 Workflow는 available=true만 보지 말고 최신성과 사용 가능 여부를 함께 확인해야 한다.
17.5 계획 컨텍스트 사용 원칙
- 컨텍스트 필드 이름을 사용자 TTS에 그대로 노출하지 않는다.
current_room_name이 있으면 자연어 공간명으로 답한다.- 스테이션 도킹 상태이면 공간 이름이 비어 있어도 “스테이션에 있다”고 안내할 수 있다.
- 공기질 원시값은 의미 등급과 권장 행동으로 변환한다.
- 실행 중인 Task가 있으면 새 Task의 실행 허용과 선점 정책에 반영한다.
- 스냅숏은 조회 시점의 정보다. 실행 직전의 중요한 조건은 DeviceAgent에서 다시 확인한다.
18. TaskManagerClient AAR
TaskManager Core는 호출 채널에 종속되지 않는다. 시스템 앱은 typed AAR, IoT는 MQTT,
Cloud·On-device bridge는 Bundle/JSON 변환을 사용하지만, 최종 요청은 같은
submitTask 또는 submitWorkflow 계약으로 수렴해야 한다.
AAR은 시스템 앱이 문자열과 Bundle을 직접 조립하지 않도록 제공하는 product-level facade다. 다음 원칙을 지킨다.
TaskSubmitRequest와TaskWorkflowRequestbuilder가 필수 필드를 검증한다.TaskManagerClientCallback.onTaskEvent가 공통 event envelope를 전달한다.- AAR은 TaskManager runtime을 포함하지 않고 DeviceAgent Binder 경계만 감싼다.
- 필드, 기본값과 callback 의미는 Core 계약과 동일해야 한다.
typed API, builder 예시와 배포 산출물은 TaskManagerClient AAR API Specification을 기준으로 한다.
19. IoT/MQTT와 Task Monitor 계약
IoT 요청은 transport metadata와 Task metadata를 분리한다. deviceId, topic,
command ack는 MQTT 계층이 소유하고, requestId, traceId, taskMethod, queue,
policy와 payload는 Task 계약으로 전달한다.
- 모의 실행과 실제 dispatch를 UI에서 구분한다.
- HTTP·MQTT 인증을 우회하는 payload 필드를 허용하지 않는다.
- 명령 ack와 물리 완료 event를 같은 상태로 취급하지 않는다.
- source가 달라도 validator, admission, executor와 completion gate를 우회하지 않는다.
전체 payload와 운영 속성은 MQTT Task Contract을 기준으로 한다.
20. 선택 연동: Cloud Planner와 A2A
20.0 선택적 상위 연동의 경계
기본 경로에는 Planner가 필요하지 않다. 앱·PUI·IoT·예약과 사전 정의 Workflow는 상위 의미 추론 없이 같은 Core를 사용한다. Planner가 연결되더라도 실행 허용, 자원 정책, 물리 완료 증거와 최종 상태 판정은 DeviceAgent TaskManager와 각 기기 도메인이 소유한다. 상위 Planner가 없어도 기기 내부에서 안전한 생명주기를 유지한다.
상위 Planner는 목표를 해석하고 capability와 단계 의존성을 구성한다. DeviceAgent는 계획을 다시 해석하지 않고 실행 가능성, 현재 상태, 안전 정책과 실제 완료 증거를 판정한다.
goal or product scenario
-> structured task/workflow
-> DeviceAgent admission and execution
-> progress/terminal evidence
-> continue locally or request bounded replanning
정상 진행마다 Planner를 호출하지 않는다. BLOCKED, FAILED, TIMEOUT 또는 명시적
사용자 변경처럼 상위 판단이 필요한 terminal event만 재계획 후보가 된다.
requestId, traceId, cloudWorkflowId, cloudStepId는 왕복 동안 보존한다.
Cloud·On-device·DeviceAgent 폐루프와 callback 계약은 Voice TaskManager Closed Loop, 기기 상태 입력은 Device Context Planning Spec을 기준으로 한다.
제5부 · 운영·보안·검증 — 21~28장은 관측성, 영속성, 보안, 실패 UX, 시험, 변경과 참조 규격을 정리한다.
21. 모니터링과 관측성
21.1 운영자가 봐야 하는 상태
| 화면 요소 | 기준 정보 |
|---|---|
| 현재 Task와 상태 | listTasks/getTaskStatus |
| 현재 Workflow 단계 | TaskRecord 단계 상태 |
| 대기열의 실행·대기 상태 | getQueueStatus |
| 실제 기기 위치와 청정 상태 | 계획 컨텍스트와 도메인 상태 |
| 완료 증거 | 완료 이벤트와 결과 |
| 실패 원인 | 실패 사유 계약 |
| 예약 목록 | getScheduledTasks |
| Planner 계획 | Cloud 실행 추적 정보 |
Task Monitor와 A2A Text Console은 같은 정보를 다른 관점으로 보여준다.
- Task Monitor: DeviceAgent의 실제 실행 상태 중심
- Text Console: Planner 판단, 요청, 콜백과 기기 컨텍스트의 연결 중심
21.2 필수 상관관계
21.3 UI에서 구분해야 하는 상태
- 접수됨과 실행 중
- 실행 중과 완료 증거 대기
- 완료와 취소
- 실패와 차단
- 현재 단계와 다음 대기 단계
- Planner 계획과 DeviceAgent 실제 진행
- 현재 컨텍스트와 계획 시점 스냅숏
21.4 운영 지표
현재 런타임은 Task 최종 결과와 대기열 상태를 바탕으로 다음 운영 지표를 만들 수 있다.
- 제출/완료/실패/부분실패/취소 수
- 대기열별 대기·실행 Task 수
- Task 실행 시간
- 재시도 수
- 시간 초과 수
- 실패 사유 코드 분포
- Workflow 단계 성공률
- 예약의 실행 허용·차단·미실행 수
- 취소·보상 동작 성공률
제품 지표는 단순 접수 비율이 아니라 실제 완료 증거를 기준으로 산정해야 한다.
22. 영속성·용량·런타임 설정
22.1 TaskManager 속성
persist.sys.deviceagent.taskmanager.enable
persist.sys.deviceagent.taskmanager.legacy_queue
persist.sys.deviceagent.taskmanager.queue_size
persist.sys.deviceagent.taskmanager.persist
persist.sys.deviceagent.taskmanager.persist_path
persist.sys.deviceagent.taskmanager.schedule_persist
persist.sys.deviceagent.taskmanager.schedule_persist_path
persist.sys.deviceagent.taskmanager.strict_validation
persist.sys.deviceagent.taskmanager.executor_dry_run
persist.sys.deviceagent.taskmanager.scheduler.enable
persist.sys.deviceagent.taskmanager.scheduler.interval_ms
persist.sys.deviceagent.taskmanager.scheduler.limit
persist.sys.deviceagent.taskmanager.scheduler.exact_alarm
persist.sys.deviceagent.taskmanager.resource_policy
persist.sys.deviceagent.taskmanager.cpu_limit
persist.sys.deviceagent.taskmanager.ram_pressure_limit
persist.sys.deviceagent.taskmanager.thermal_limit
persist.sys.deviceagent.taskmanager.move_timeout_ms
persist.sys.deviceagent.taskmanager.clean_dwell_ms
22.2 기본값
| 항목 | 기본값 |
|---|---|
| 대기열 용량 | 64 |
| Task·예약 기록 상한 | 100 |
| 일반 시간 제한 | 30초 |
| 예약 저장소 | /mnt/data2/db/taskmanager_scheduled_tasks.json |
| TaskManager 활성화 속성 기본값 | true |
| 기존 명령 대기열 속성 기본값 | true |
| 일반 Task 스냅숏 영속 저장 | false |
| 지연 예약 영속 저장 | true |
| 엄격한 입력 검증 | false |
| 실행기 모의 실행 | false |
| 예약 실행 주기 확인·정확한 알람 | false / false |
| 예약 확인 주기·묶음 상한 | 30초 / 20 |
| 시스템 자원 정책 | false |
| CPU / RAM / thermal threshold | 90 / 90 / 4 |
| movement timeout | 120초 |
| cleaning dwell | 0ms |
| 모니터 상태 보고·명령 조회 | false / false |
22.3 영속성 원칙
- 최종 상태의 실행 기록은 디버깅과 운영 분석을 위해 제한적으로 보존한다.
- 장기 보관은 DeviceAgent 메모리 내 기록이 아니라 외부 관측 저장소가 담당한다.
- 부팅 복원 시
RUNNING을 그대로 재개했다고 가정하면 안 된다. - 기기 동작 Task를 다시 실행하기 전에 멱등성과 현재 상태를 확인한다.
- 예약 저장소 쓰기 실패를 등록 성공으로 숨기면 안 된다.
현재 일반 Task 영속성은 persistTaskSnapshot()이 Task ID, 메서드, 대기열,
상태, 진행률과 시각을 JSON으로 남기는 쓰기 전용 진단 스냅숏이다. 이를
읽어 TaskRecord와 비동기 실행을 복원하는 런타임은 없다. 반면 지연 예약은
허용된 Bundle 키를 저장하고 ScheduledTaskRecord를 다시 읽는 별도 경로가 있다.
두 영속성 기능을 같은 수준의 장애 복구 기능으로 표현하면 안 된다.
22.4 용량 관리 원칙
- 대기열 포화는
DEVICE_BUSY로 정규화한다. - 빈도가 높은 센서 갱신은 Task 대기열로 보내지 않는다.
- 연결 상태 보고와 진행 이벤트는 표본 추출과 빈도 제한을 적용한다.
- 장기 Workflow가 대기열 작업자를 과도하게 점유하지 않도록 도메인 콜백 기반 대기와 전용 런타임 분리를 검토한다.
23. 보안과 권한
23.1 Binder 경계
TaskManager API는 DeviceAgent Binder를 통과한다. 제품 배포에서 확인할 항목:
- DeviceAgent와 클라이언트 APK 인증서
- 서명 권한
- 패키지 UID와 설치 경로
- 외부 공개 컴포넌트
- 콜백 클래스 등록
- 호출자 식별 검증
23.2 시스템 앱 배포
- DeviceAgent와 MaumAi·온디바이스 Agent는 디버그 인증서로
/system/priv-app에 배포하면 안 된다. - 플랫폼 인증서를
apksigner verify --print-certs로 비교한다. - 파일 소유자, 권한 모드와 SELinux 컨텍스트를 확인한다.
- APK 교체 전 원본을 백업한다.
- 빌드 성공은 부팅과 Binder 연결 성공을 의미하지 않는다.
23.3 모니터 전송 보안
- Bearer 토큰 없는 제품 외부 전송은 금지한다.
- 테스트 콘솔 수신기는 제품 형상의 외부 공개 정책을 별도로 검토한다.
- endpoint는 HTTPS를 기본으로 한다.
- 기기 ID와 토큰을 문서, Git과 UI 기본값에 직접 넣지 않는다.
- 명령 조회와 이벤트 확인 응답에는 재전송 공격과 중복 실행 방어가 필요하다.
23.4 특권 우회 필드
다음 필드는 일반 외부 호출자에게 직접 노출하지 않는다.
bypassCallerPolicyforceTaskManager의 무제한 사용requiredResources임의 축소executorDryRun=false원격 강제replace_all긴급 선점
24. 실패 처리와 사용자 UX
24.1 구조화 실패에서 사용자 문장으로
reason_code=ROOM_NOT_FOUND
reason_params.target_location_name=거실
suggested_action=ASK_USER_TARGET
사용자 응답:
“거실은 등록된 공간에서 찾지 못했어. 등록된 다른 공간으로 이동할까?”
내부 필드를 그대로 TTS로 읽지 않는다.
나쁜 예:
context 기준으로 current_room_id=0입니다.
CAPABILITY_UNAVAILABLE reason_params가 발생했습니다.
좋은 예:
현재 스테이션에 있어.
요청한 공간을 찾지 못했어. 공간 이름을 다시 알려줘.
24.2 실패 후 동작
| 실패 | 기본 안내 | 실행 정책 |
|---|---|---|
| 공간 없음 | 가능한 공간 안내 또는 질문 | 재계획 전 기기 동작 금지 |
| 저전력 | 복귀 안내 | 도킹 후 재개 가능 |
| 사용 중 | 현재 작업 설명 | 대기·재시도·취소 중 선택 |
| 경로 차단 | 장애물 제거 요청 | 사용자 확인 전 반복 이동 금지 |
| 사용자 취소 | 취소 확인 | Workflow 종료 |
| 기능 없음 | 지원 범위 설명 | 임의로 다른 기능 실행 금지 |
| 시간 초과 | 지연 또는 실패 설명 | 최신 상태 확인 후 재시도 판단 |
25. 테스트 전략과 인수 기준
25.1 테스트 계층
| 계층 | 확인 대상 | 한계 |
|---|---|---|
| 단위 시험 | 정책, 검증기, 실패 사유와 Bundle 변환 | 실제 Binder와 하드웨어 없음 |
| JVM 통합 시험 | TaskManager 기록, 대기열과 Workflow | Android 런타임 차이 |
| 빌드 | DeviceAgent와 AAR 컴파일·패키징 | 실행 연결 미확인 |
| 계측 시험 | Binder와 DeviceAgent 경로 | 일부 도메인 하드웨어 제한 |
| 실기기 모의 실행 | 요청 구조, 이벤트와 모니터 | 실제 기기 동작 미실행 |
| 실기기 실제 실행 | 이동, 청정, 화면과 세션의 완료 증거 | 특정 기기 상태에 의존 |
| 장시간·재부팅 시험 | 영속성, 예약과 고립 Task 복구 | 장시간 필요 |
25.2 최소 기능 검증
- DIRECT 조회 성공과 실패
- ASYNC Task 접수 후 최종 이벤트
- QUEUED_WAIT 시간 초과
- 같은 대기열의 실행 순서
- 우선순위 순서
- 대기열 포화
- 엄격한 입력 검증 거절
- 요청 출처별 긴급 우선순위 거절
- 상태·자원 실행 허용 거절
- 대기·실행 Task 취소
- 취소 명령 실패
- 보상 동작 실행
- 순차 Workflow
- 병렬 그룹 성공과 부분 실패
- 조건에 따른 생략과 실패
- 선행 단계 기준 지연
- 과거 완료 증거 재사용 방어
- PUI 취소 콜백
- 예약 중복 제거, 저장, 복원, 실행, 취소와 미실행 처리
- 이벤트 상관관계와 모니터 표시
25.3 도메인별 실기기 인수 시험
| 도메인 | 반드시 확인할 증거 |
|---|---|
| Movement | 실제 출발, 목표 도착, 시간 초과, 정지와 스테이션 충전 |
| Cleaning | 시작, 실행, PUI 중지, 자연 종료, 결과 보고와 복귀 |
| TTS | 재생 시작·종료, 호출어 취소와 중지 |
| UI·Vital Sign | 화면 적용, 앱 실행, 측정 완료와 사용자 취소 |
| Security | 시작, 일시정지, 재개, 중지, 저전력과 순찰 완료 |
| Schedule | 재부팅 복원, 정확한 실행 시각, 미실행과 시계 변경 |
| Monitor | 이벤트 누락·중복, 인증과 오프라인 복구 |
25.4 기존 검증 증거 해석
기존 문서에는 다음 수준의 증거가 있다.
submitTask,submitWorkflow, 조회·대기열·관리 제어 API의 계측 확인 기록- 실기기 TaskManager 계측 시험 통과 기록
- Cloud·On-device 요청 구조와 콜백 분배 확인 기록
- 예약 등록, 복원과 실행 시각 관련 실기기 검증 기록
- 이동을 제외한 혼합 Workflow 검증 기록
이 기록은 당시 기기와 APK 조합에 한정된 증거다. MR6 소스, 서명 또는 빌드 산출물이 바뀌면 출시 인수 시험을 다시 수행한다.
25.5 출시 판정 기준
위 구조도의 Gate 1~10은 API 정합에서 입력 검증, 실행기, 완료 증거, 취소·보상, 실패 사유, Binder 보안, 실기기 시험, 장시간 시험, 관측성과 원복까지 순서대로 확인한다.
26. 현재 구현의 한계와 목표 확장
26.1 현재 확인된 한계
| 영역 | 현재 한계 | 영향 |
|---|---|---|
| 입력 검증 | 기본적으로 엄격 검증 비활성 | 잘못된 기존 입력이 실행 직전에 실패할 수 있음 |
| 기본 정책 | 메서드 이름을 바탕으로 추정 | 신규 메서드 오분류 가능 |
| 대기열 별칭 | queue와 queueKey 차이 |
설정값 불일치 가능 |
| 결과 취합 정책 | 값을 보존하지만 모든 하위 Task 대기 중심 | 하나 성공·정족수 완료 방식 미지원 |
| 실행 조건 | 단계 완료·출력 일치 중심 | 숫자와 복합 조건식 제한 |
| 장기 지연 | Workflow 스레드에서 대기 | 매우 긴 지연에 부적합 |
| 영속성 | 메모리 상태와 실제 상태의 재정합 제한 | 재부팅 후 고립·중복 Task 위험 |
| 멱등성 | 일부 경로만 requestId 사용 |
기기 동작 재실행 방어 확대 필요 |
| 자원 점유 | 일부 도메인 충돌만 명시 | 카메라·화면·이동의 공통 점유 계약 미완성 |
| 완료 판정 | 도메인별 완료 증거 범위 편차 | 요청 접수를 실제 완료로 오해할 위험 |
| 모니터 | HTTP 조회와 POST 중심 | 오프라인 대기열과 확인 응답 생명주기 보강 필요 |
| 기능 계약 불일치 | AAR, DeviceAgent와 Planner 기능 목록 분산 | 계층 간 메서드 불일치 가능 |
26.2 목표 확장
- 기능 설명자에서 정책, 스키마, 실행기와 완료 증거를 일관되게 생성한다.
- 요청 진입점에서
queue별칭을 표준 이름으로 완전히 정규화한다. - 엄격한 입력 검증을 단계적으로 기본 활성화한다.
- 자원 점유 계약을 카메라, 화면, 스피커, 이동과 앱 세션으로 확장한다.
- 이벤트 기반 Workflow 재개로 긴 대기를 대기열 작업자에서 분리한다.
- 장애·재부팅 복구와 멱등성 원장을 강화한다.
- 실행 조건을 타입 기반 연산자로 확장한다.
- Task·이벤트 스키마의 버전 전환 절차를 정의한다.
- AAR, DeviceAgent와 Cloud 기능 목록의 불일치를 CI에서 검사한다.
- 도메인별 완료 증거 범위표를 출시 판정 기준으로 운영한다.
26.3 선택적 상위 계획 연동과 Core 안정성
동적 목표 해석, 상태 관찰과 기능 조합은 TaskManager 위의 선택 확장이다. Core는 다음을 유지해야 한다.
- 일반 단일 명령의 응답 시간을 늘리지 않는다.
- 정상 Task마다 Planner를 재호출하지 않는다.
- 상위 Planner 장애 시에도 현재 Task를 안전하게 종료한다.
- 기능이 없으면 차단 상태로 남기고 다른 기능으로 임의 치환하지 않는다.
- 재계획 횟수와 도구 사용 횟수에 상한을 둔다.
27. 구현 변경 절차
27.1 신규 메서드 추가
TaskMethods의 public/internal 상수를 추가한다.TaskSupportedCommands의 도메인 그룹을 추가한다.TaskBundleValidator입력 스키마를 추가한다.TaskPolicyRegistry의 정확한 실행 정책을 추가한다.- 기기 도메인
TaskExecutor를 구현하고 등록한다. - 별칭 변환기 적용 여부를 확인한다.
- 완료 대상과 Completion Bridge를 연결한다.
- 취소와 보상 동작을 정의한다.
- 실패 사유 매핑과 컨텍스트 필드를 정의한다.
- AAR API 사양과 llmwiki를 갱신한다.
- 단위, 기기 계측과 실기기 시험을 수행한다.
27.2 기존 메서드 수정
- method 문자열은 호환성 영향이 크므로 alias를 먼저 추가한다.
- field type 변경은 JSON→Bundle bridge와 AAR builder를 함께 수정한다.
- timeout 변경은 workflow timeout 계산과 실기기 duration 근거를 확인한다.
- 완료 조건 변경은 콜백 제공자와 감시기를 함께 수정한다.
- queue 변경은 concurrency와 preempt 동작을 회귀 테스트한다.
27.3 문서 변경
| 변경 | 함께 갱신할 문서 |
|---|---|
| public method/field | 이 사양서, AAR API, DeviceAgent API contract |
| 이벤트·실패 사유 | 이 사양서, 콜백 완료 판정, 모니터 |
| schedule | 이 사양서, scheduling readiness/roadmap |
| Cloud shape | 이 사양서, voice closed-loop/data-flow |
| 완료 연결부 | 이 사양서, 콜백 완료 판정 |
| 제품 인수 시험 | implementation worklog와 validation report |
28. 참조 규격과 문서 색인
이 사양서는 Core 규범을 소유한다. 상세 문서는 한 가지 책임만 갖고, 같은 계약을 다시 정의하지 않는다.
| 목적 | 기준 문서 |
|---|---|
| 개념과 도입 효과 | AS-IS / TO-BE 가이드 |
| DeviceAgent 구현 | Source-Level Implementation Guide |
| 시스템 앱 typed API | TaskManagerClient AAR API |
| DeviceAgent API·event·reason | DeviceAgent API Contract |
| IoT/MQTT | MQTT Task Contract |
| 예약·지연 실행 | Scheduling Runtime Readiness |
| 기기 planning context | Device Context Planning Spec |
| capability 조합 | Capability Composition Catalog |
| Cloud·On-device 폐루프 | Voice TaskManager Closed Loop |
| 운영 관측과 검증 | TaskManager Live Monitor |
| PUI·Voice 경계 | PUI and Voice Task Design Hub |
| LLM/MCP 표현 | TaskManager LLM/MCP Mapping |
| 업체 구현·인수 | Vendor Implementation Workbook |
| 압축 설명 자료 | TaskManager 핵심 설명 자료 |
해석 충돌 시 제품 안전 정책과 승인된 요구사항, 이 사양서, 세부 계약 문서, 검증 기록 순서로 판단한다. 통합된 이전 문서는 기존 URL의 리다이렉트로만 유지하며, 활성 검색과 신규 링크에서는 사용하지 않는다.
제6부 · 상세 규범과 호환성 — 29~31장은 Core 불변 조건, 도메인별 Task 사양, 기존 시스템 전환과 적합성 판정을 고정한다.
29. TaskManager Core, 관리 대상 Task와 기기 연동 규범
이 장은 앞의 구현 설명을 제품 사양의 세 계층으로 정리한다. TaskManager가 공통으로 보장할 사양, 각 Task가 개별적으로 선언할 사양, 실제 기기 상태가 실행 허용과 완료에 미치는 영향을 분리한다.
위 3계층 계약 구조도는 모든 Task에 공통인 TaskManager Core 사양, 기능별 입력·정책·완료·취소를 정의하는 관리 대상 Task 단위 사양, 실제 제품 상태와 자원 제약을 제공하는 기기 도메인 연동 사양을 분리한다.
이 세 층을 섞으면 다음과 같은 오류가 생긴다.
- TaskManager가 요청을 접수했지만 기존 DeviceAgent 정책에서 뒤늦게 거절된다.
- 메서드가 반환됐다는 이유만으로 물리 동작을 완료 처리한다.
- LLM 활성 중 신규 동작 제한과 이미 수행 중인 동작의 일시정지·재개를 같은 정책으로 오해한다.
- 장기 앱 세션을 화면 전환 ACK만으로 완료 처리한다.
- Planner가 기기 상태를 참고했어도 DeviceAgent의 최종 안전 정책을 우회하게 된다.
29.1 TaskManager Core 규범 사양
TaskManager Core는 기능의 내용이 아니라 실행의 질서와 증거를 소유한다.
| 사양 축 | Core가 관리해야 하는 값 | 현재 구현 기준 | 규범 |
|---|---|---|---|
| 식별 | taskId, taskMethod, workflowName, 요청·추적 ID 연계 |
TaskRecord와 요청 메타데이터 |
모든 실행과 콜백은 Task 또는 Workflow로 상관관계를 복원할 수 있어야 함 |
| 접수 | 활성화, 별칭, 스키마, 출처, 상태, 자원, 선점 | 6장의 실행 허용 순서 | 실행기 호출 전에 실패를 구조화해 반환해야 함 |
| 정책 | 실행 방식, 대기열, 우선순위, 시간 제한, 재시도, 취소 가능 여부 | TaskPolicyRegistry |
출시 대상 기능은 이름 기반 추정이 아니라 명시적 정책을 가져야 함 |
| 실행 | 직접·대기·비동기 실행, 대기열 용량과 작업자 소유권 | 대기열별 실행기와 상위 Workflow | 같은 대기열의 순서와 서로 다른 대기열의 병렬성을 예측 가능하게 유지해야 함 |
| 상태 | 대기·실행·취소 중·최종 상태 | TaskRecord |
최종 상태는 성공, 실패, 부분 실패와 취소를 구분해야 함 |
| 완료 | 대상, 식별 키, 관찰 시작 시점, 안정 시간, 시간 제한 | TaskCompletionWatcher |
실행 요청의 ACK와 실제 완료를 분리해야 함 |
| 제어 | 취소, 선점과 보상 동작 | 취소 명령과 Future |
취소 요청과 실제 기기 중단 확인을 구분해야 함 |
| 실패 | 오류, 사유 코드, 매개변수, 복구 가능성과 권장 조치 | TaskReasonContract |
사용자 안내와 상위 재계획이 가능한 구조를 유지해야 함 |
| 관찰 | 이벤트, 진행률, 대기열·Task 스냅숏과 계획 컨텍스트 | 상태 보고기·제공자 | 상태 표시 계층이 Task의 실제 상태를 새로 정의하면 안 됨 |
| 복원 | Task·예약 상태 저장과 재조정 | 일반 Task와 단발 예약을 별도 관리 | 저장된 상태보다 부팅 후 확인한 최신 기기 증거를 우선해야 함 |
29.1.1 Core 불변 조건
- Task 접수 성공은 기능 완료가 아니다.
accepted=true는 실행 허용 판정과 기록 생성에 성공했다는 뜻이다. - 물리 Task의 성공은 최신 완료 증거로 확정한다.
completionSinceMs보다 오래된 콜백은 사용할 수 없다. - 취소는 성공으로 변환하지 않는다. 사용자 취소, PUI 중단, 외부 앱 종료를 목적 달성으로 해석하지 않는다.
- TaskManager는 기기 도메인 안전 정책보다 높은 권한을 갖지 않는다. 대기열 우선순위가 배터리, 오류, 개인정보 보호와 제품 모드 제한을 우회하지 않는다.
- 관찰 이벤트는 실행 명령이 아니다. 센서 값이나 콜백을 그대로 구동 Task로 다시 제출하지 않는다.
- 상위 Planner 장애가 현재의 안전한 동작을 깨면 안 된다. 정상적인 후속 실행과 기기 내 취소·시간 제한 처리는 기기에서 마감한다.
- 같은 물리 효과를 만드는 중복 제출을 식별할 수 있어야 한다. 요청·추적·Workflow·단계 ID를 보존한다.
- 지원하지 않는 기능을 유사 기능으로 임의 대체하지 않는다. 실행기나 필수 입력이 없으면 명시적으로 거절한다.
29.1.2 실행 허용 정책과 실행 중 정책의 차이
실행 허용 정책은 두 시점에 적용된다.
| 시점 | 주요 구현 | 판단 대상 | 특징 |
|---|---|---|---|
| TaskManager 실행 허용 | TaskManager, TaskDomainResourcePolicy, TaskResourcePolicy |
구조화 요청, 주 상태 조건, 자원 점유, CPU·RAM·발열 | 실행 전에 빠르게 거절 가능 |
| 기기 도메인 실행 | CmdPolicyManager, StateManager, WSS·Movement·Cleaning manager |
실제 LLM, 배터리, AMR, 개인정보 보호, 오류와 현재 동작 | 제품 사양의 최종 판단 주체 |
따라서 TaskManager가 accepted=true를 반환해도 기기 도메인 실행 시점에 상태가 바뀌면 POLICY_NOT_ALLOWED 또는 도메인 오류로 실패할 수 있다. 목표는 도메인 규칙을 TaskManager에 복제하는 것이 아니다. 공통으로 표현할 수 있는 상태와 자원을 실행 허용 판정에 반영하되, 최종 도메인 판정을 유지하는 것이다.
29.2 관리 대상 Task 단위 규범 사양
관리 대상 Task는 단순한 “함수 이름과 매개변수 묶음”이 아니다. 최소한 다음 다섯 질문에 답할 수 있어야 한다.
관리 대상 기능은 다음 질문에 모두 답할 수 있어야 한다.
- 무엇을 실행하는가?
- 어떤 상태와 자원이 있어야 시작할 수 있는가?
- 언제 실제 완료로 판단하는가?
- 어떻게 중단하고 복구하는가?
- 실패 후 누가 다음 결정을 하는가?
29.2.1 Task 설명자 필드
| 구분 | 필드 | 필수 조건 | 의미 |
|---|---|---|---|
| 식별 | taskMethod |
항상 필수 | 표준 실행기 연결 키 |
| 식별 | source |
제품 요청에서 필수 권장 | VOICE, APP, PUI, IOT, CLOUD, SENSOR 등 |
| 식별 | requestId, traceId |
외부·복합 요청에서 필수 | 중복 실행 방지와 전체 실행 추적 |
| 상하 관계 | Workflow·단계 ID | Workflow 단계이면 필수 | 상위 Task, 의존관계와 콜백 연결 |
| 입력 | 메서드별 매개변수 | 메서드 스키마에 따라 필수 | 공간, 동작, 모드, 화면, 스케줄 ID 등 |
| 실행 | executionMode |
정책 기본값 사용 가능 | 반환 시점과 대기열 사용 방식 |
| 실행 | queueKey |
정책 기본값 사용 가능 | 동시성과 순서 제어 영역 |
| 실행 | priority |
정책 기본값 사용 가능 | 대기열 내 실행 우선순위 |
| 실행 | timeoutMs, 재시도 |
장기 Task에서 명시 권장 | 무한 대기 방지와 재시도 상한 |
| 실행 허용 | requireMainState |
특정 모드 전용 Task | 요구 주 상태 |
| 실행 허용 | checkBlockedStatus |
기존 차단 상태를 실행 허용 판정에 적용할 때 | StateManager.checkBlockedStatus() 사용 |
| 실행 허용 | requiredResources |
카메라·화면·세션 공유 기능 | 구조화된 자원 요구사항 |
| 완료 | completionTarget |
비동기 물리·세션 Task | 기다릴 실제 완료 증거 종류 |
| 완료 | completionKey 또는 공간 ID |
완료 조건이 식별자를 요구할 때 | 다른 Task의 이벤트와 구분 |
| 완료 | completionSinceMs |
감시기 진입 전 내부 설정 | 과거 이벤트 차단 |
| 완료 | completionStableMs |
흔들리는 상태일 때 | 일정 시간의 안정 조건 |
| 제어 | cancellable, cancelMethod |
장기·기기 동작 Task | 중단 가능성과 실제 중지 함수 |
| 복구 | compensationMethod |
선행 동작 복구가 필요할 때 | 부분 실행 뒤 안전 상태 복원 |
| 실행 구성 | 시작 조건, 실행 조건, 지연, 실패 정책 | Workflow 단계에서 필요할 때 | 순서, 시간, 조건과 실패 전파 |
현재 TaskPolicyRegistry.resolve()는 요청이 정책 기본값을 덮어쓸 수 있게 한다. 그러나 호출자가 임의로 대기열, 우선순위와 시간 제한을 바꿔도 된다는 뜻은 아니다. 외부 공개 AAR과 Cloud 계약에는 기능 설명자가 허용한 변경 항목만 노출해야 한다.
29.2.2 Task 유형별 필수 사양
| Task 유형 | 적합한 실행 방식 | 완료 기준 | 취소·복구 | 대표 예 |
|---|---|---|---|---|
| 즉시 조회 | DIRECT | 메서드 결과와 출처 정보의 최신성 | 일반적으로 취소 없음 | 배터리, 상태, 지도 존재 여부 |
| 제한된 설정 변경 | QUEUED_WAIT | 적용 응답 또는 재조회 확인 | 재설정·원복 필요 여부 | 설정, Eye LED, 런처 화면 |
| 물리 이동 | ASYNC | 도착 위치와 이동 정지 또는 충전 상태 | 이동 정지, 필요 시 안전 복귀 | 이동, 스테이션 복귀 |
| 장기 청정 | ASYNC | 시작·정지·단계·보고서 증거 | 청정 정지, 보고·복귀 보상 동작 | 기본·선택 청정 |
| 음성 출력 | ASYNC | 재생 시작·종료 또는 중단 | TTS 중지 | 안내 발화 |
| 외부 앱 세션 | ASYNC | 앱 세션 시작·종료 | 앱 취소 또는 화면 복구 | 바이탈사인 |
| 보안 세션 | ASYNC | 시작·일시정지·재개·종료 | 보안 중지 | 감시 모드 |
| 상호작용 세션 | ASYNC | 동작 단계와 상호작용 완료 | 상호작용 중지 | Welcome·Wakeup·Relax |
| 의미 관찰 | DIRECT 또는 QUEUED_WAIT | 최신 관찰 결과 | 관찰 중단·자세 복구 | Vision, 스테이션 신호 |
| 제품 스케줄 변경 | QUEUED_WAIT | DB 재조회 또는 콜백 | 변경 유형별 원복 | 스케줄 추가·수정·삭제 |
| 단발 예약 Task | 예약 런타임 | 실행 시점의 새 실행 허용 결과 | 예약 취소 | 30분 뒤 단일 실행 |
| 상위 Workflow | ASYNC/QUEUED_WAIT | 필수 단계의 최종 상태 취합 | 하위 단계 취소·보상 동작 | 이동→청정→복귀 |
29.2.3 Task 최종 상태 판정
| 결과 | 판정 조건 | 다음 Workflow 단계 |
|---|---|---|
COMPLETED |
선언한 성공 증거가 최신성과 안정 조건을 만족 | 의존관계가 충족되면 진행 |
FAILED |
요청 전달 거절, 시간 초과, 중단 또는 실행기 예외 | 실패 정책에 따라 중단·계속·상위 판단 |
PARTIAL_FAILED |
병렬 그룹 일부 성공, 일부 실패 | 성공한 기기 동작과 실패 목록을 함께 보존 |
CANCELLED |
취소 경로와 실제 중단이 확인됨 | 기본적으로 성공 의존관계를 만족하지 않음 |
시간 제한은 완료 조건을 대신하지 않는다. 제한 시간이 지나면 성공으로 처리하지 않고 FAILED 또는 세션별 명시 정책으로 마감한다. 바이탈사인처럼 사용자의 측정 완료나 취소로 끝나는 Task는 임의로 30초 뒤 완료 처리하지 않는다. 앱의 완료·취소 증거를 기다려야 한다.
29.3 LLM/음성 세션과 기기 동작 연동 사양
이 절은 TaskManager 전체 요청 경로를 음성 중심으로 설명하지 않는다. LLM·음성 세션이 마이크, 스피커와 추론 자원을 점유할 때 추가로 적용되는 도메인 제약만 정의한다.
“LLM 동작 중 다른 동작 제한”은 하나의 boolean 규칙이 아니다. 현재 구현에는 신규 명령 실행 제한, 기존 동작 일시정지·재개, LLM 상태 관찰이 별도로 존재한다.
29.3.1 LLM 상태 모델
LlmPipelineObservationBridge는 다음 상태를 planning context의 voice_llm으로 투영한다.
| 파이프라인 상태 | 처리 중 | 음성 세션 활성 | 의미 |
|---|---|---|---|
idle |
false | false | 음성 세션 없음 |
listening |
true | true | STT 처리 |
cloud_reasoning |
true | true | Cloud 추론 |
on_device_reasoning |
true | true | 온디바이스 추론 |
synthesizing_llm |
true | true | LLM 응답 TTS 합성 |
speaking_llm |
true | true | LLM 응답 재생 |
paused |
false | true | 세션은 유지되지만 파이프라인 일시정지 |
stopped |
false | false | LLM 중지 |
initializing, reinitializing |
false | false | 준비 중 |
command_requesting |
true | true | 기기 명령 요청 중 |
| 외부 TTS 합성·재생 | true | false | 외부 발화이며 음성 세션과 구분 |
이 값은 ondevice_agent_reported_status를 기반으로 하며 유효 시간과 최신성 조건이 있다. 오래된 상태를 Planner의 실행 근거로 사용하면 안 된다.
29.3.2 신규 기기 동작 제한
CmdPolicyManager.commonCheck()는 LlmManager.isLlmProcessingStatus()가 true인 동안 일반 이동, 청정과 스케줄 계열의 신규 동작을 기본적으로 거절한다.
현재 예외는 다음과 같다.
- 공기 센서 자동 청정 호출은 제한적으로 허용한다.
- 저전력/에러에 의한 안전 복귀는
CHK_OPT_IGNORE_LLM으로 LLM 제한을 우회할 수 있다. - 이 우회는 안전·내부 복구용이며 일반 Cloud·VOICE Task에 노출하면 안 된다.
중요한 현재 경계:
- TaskManager Core의
TaskDomainResourcePolicy는 아직 모든 물리 Task에voice_session자원을 자동으로 할당하지 않는다. - 따라서 LLM 활성 상태의 일반 Task가 TaskManager의 실행 허용 판정을 통과한 뒤 기존 기기 도메인 정책에서 거절될 수 있다.
- 계획 컨텍스트의
voice_llm.pipeline_busy는 Planner 입력이지만, 이것만으로 DeviceAgent의 최종 정책을 대체하지 않는다.
29.3.3 기존 동작 일시정지·재개
호출어가 감지되면 notifyLearnedKeywordDetected 경로가 setDeviceStatus(action=pause)를 호출한다. 이 경로는 현재 활성 domain 중 하나를 pause한다.
| 현재 실행 도메인 | 일시정지 연결 지점 |
|---|---|
| 청정 | cleanPause() |
| 상호작용 | InterScheduleManager.pause() |
| 이동 | RobotMovementController.pauseCurrentMove() |
LLM 처리가 끝나고 기기 동작이 일시정지 상태이면 setLlmStatus 경로가 재개를 시도한다. 일시정지 요청자는 목록으로 관리된다. 따라서 필터 커버 오류처럼 LLM 외 다른 원인이 남아 있으면 LLM 종료만으로 재개하지 않는다. E01/S08 같은 오류 상태도 재개를 막는다.
persist.sys.debug.deviceagent.maumai_tmp_pause_resume는 LLM 상태 변화만으로 일시정지·재개를 연결하는 임시 속성이다. 기본 활성 사양으로 간주하면 안 된다. 제품 기준은 호출어, 명시적 기기 상태 생명주기와 실제 오류 조건을 함께 확인한다.
29.3.4 LLM 연동 규범
- 사용자의 음성 세션 시작을 위해 현재 Workflow를
COMPLETED로 만들지 않는다. 필요한 도메인만 일시정지한다. 현재TaskRecord에는 별도PAUSED상태가 없어 기록은RUNNING으로 남으므로, 도메인 일시정지 사실은 단계·이벤트로 보강해야 한다. - 음성 세션 중 새 물리 Task는 기기 도메인 정책이 허용할 때만 실행한다.
- 안전 복귀 같은 긴급 경로는 일반 사용자 우선순위와 분리한다.
- 재개는 LLM IDLE 상태만 보지 않고 일시정지 요청자와 현재 오류를 확인한다.
voice_session_active,pipeline_busy,output_state를 구분한다. 외부 TTS 재생을 사용자 음성 추론 세션으로 오해하지 않는다.- Task 이벤트에는 “LLM 때문에 실행 허용 거절”, “LLM으로 기존 동작 일시정지”, “다른 오류 때문에 재개 보류”를 서로 다른 실패 사유로 노출해야 한다.
29.4 기기 상태와 자원 연동 행렬
아래 표의 Core는 TaskManager의 실행 허용과 런타임을, 기기 도메인은 기존 DeviceAgent의 기능 정책을 뜻한다.
| 기기 상태·자원 | 현재 관찰 출처 | 현재 실행 영향 | 소유 계층 | Task 처리 규범 |
|---|---|---|---|---|
| LLM 파이프라인 처리 중 | LlmManager, voice_llm 컨텍스트 |
일반 이동·청정·스케줄의 신규 실행을 도메인이 기본 거절 | 기기 도메인 + Planner 컨텍스트 | 대기·거절 사유를 보존하고 안전 예외만 허용 |
| 호출어·음성 세션 시작 | notifyLearnedKeywordDetected |
실행 중인 청정·상호작용·이동 일시정지 | 기기 도메인 | Task를 최종 상태로 닫지 않고 일시정지 의미 유지 |
| LLM IDLE | 보고된 상태 | 일시정지 요청자가 해제되고 오류가 없으면 재개 | 기기 도메인 | 무조건 재개하지 않고 여러 일시정지 원인을 확인 |
| Factory·ICT·Upgrade·Selftest | StateManager.mainState |
제품 일반 동작 불가 | 기기 도메인 | 기기 동작 Task는 거절하고 조회·복구 허용 범위는 별도 정의 |
| Vital Sign 주 상태 | StateManager |
다수 기존 API 차단, 카메라·화면·세션 점유 | Core 자원 + 기기 도메인 | 다른 카메라·화면 Task를 차단하고 종료 증거까지 세션 유지 |
| 실시간 스트리밍 | 주 상태 | 이동·청정·스케줄 일부 차단, 카메라·화면 점유 | Core 자원 + 기기 도메인 | Vision·Vital Sign·Security와 충돌 처리 |
| Multi AP·스케줄 편집·Wizard | 주 상태 | 일반 명령 정책 거절 | 기기 도메인 | 해당 모드 종료 후 재시도 또는 사용자 안내 |
| Security 활성 | WSS 상태·트랜잭션 | 카메라, 이동 기반부와 Security 세션 점유 | Core 자원 + 기기 도메인 | 신규 이동·Vision·Vital Sign 충돌. 일시정지·재개·중지는 항상 도달 가능해야 함 |
| 이동 중 | 이동 제어기 | 다른 일반 이동과 동시 실행 제한 | 기기 도메인 + 이동 대기열 | 같은 이동 기반부를 쓰는 Task 직렬화, 취소·도착 증거 필요 |
| 청정 중 | 청정 트랜잭션 | 새 청정·일반 이동 정책과 충돌 가능 | 기기 도메인 + 청정 대기열 | 관리 대상 이동은 청정을 중지하고 cleaning.stopped 증거를 확인한 뒤 실행 가능 |
| 상호작용 실행 중 | 상호작용 관리자 | 새 이동·청정·스케줄과 충돌 가능 | 기기 도메인 + 상호작용 대기열 | 일시정지·재개·완료 콜백 보존 |
| 긴급 저전력 | 오류 상태 | 일반 동작 금지. 현재 코드에서는 스테이션 기본 청정 허용 검사가 긴급 저전력 검사보다 먼저 수행됨 | 기기 도메인 | 의도된 예외인지 확정하고 실행 순서 시험으로 고정 |
| 저전력 | 오류 상태 | 이동·이동청정·스케줄 제한 | 기기 도메인 | 스테이션 고정 청정 예외와 안전 복귀를 구분 |
| AMR 미연결 | AMR 서비스·도킹 가능 여부 | 이동 계열 제한 | 기기 도메인 | 모의 실행이 아닌 실기기에서는 이동을 시작하지 않음 |
| 개인정보 보호 모드 | 설정 | 이동 계열 제한 | 기기 도메인 | 해제 요청을 안내하고 안전 복귀 예외는 분리 |
| A1 초기화 전 | 초기화 상태 | 일반 동작 제한 | 기기 도메인 | 컨텍스트 준비 상태를 확인하고 실행 보류 |
| 지도 편집 중 | MapManager.isEditMap() |
이동·청정 계획 실행 제한 | 기기 도메인 | 지도 편집 완료 후 최신 공간 목록으로 재계획 |
| 공간 미등록 | 지도 공간 목록 | 이동 대상 연결 실패 | 실행기 | unknown_move_target으로 실패하고 임의 공간 치환 금지 |
| 이미 스테이션 | 스테이션 상태 | 복귀 명령은 추가 동작 없이 성공 가능 | 이동 실행기 | 스테이션·충전 증거와 결과 반환 |
| CPU·RAM 압력 | TaskResourceMonitor |
NORMAL 이하 Task 실행 거절 가능 | Core, 선택 적용 | resourcePolicyEnabled가 켜졌을 때만 적용 |
| 발열 단계 | TaskResourceMonitor |
긴급 미만 Task 실행 거절 가능 | Core, 선택 적용 | 기본 임계값 4와 센서 최신성 확인 |
| AWS IoT 단절 | 네트워크 컨텍스트 | 모든 기기 내부 Task를 자동 차단하지 않음 | Planner·Domain별 | Cloud 콜백이 필요한 Task와 기기 내부 Task를 구분 |
| 잠금 모드 | 설정 | IDLE이 아닌 LLM 상태 처리와 일부 UI·LLM 기능 제한 | 기기 도메인 | 잠금 상태를 고려해 사용자 응답과 실행 경로 분리 |
29.4.1 현재 자원 요구 계약
| 자원 | 현재 점유 도메인 | 요청 예 |
|---|---|---|
movement_base |
Security | rotate, vision stationary observation |
camera |
streaming, vital sign, Security | vision observation, vital sign, Security |
foreground_display |
streaming, vital sign | vital sign/전면 화면 세션 |
external_app_session |
vital sign | 앱 세션 기반 장기 task |
security_session |
Security | Security lifecycle |
현재 speaker, microphone, tilt_head, voice_session, map_writer, network_uplink은 공통 자원 점유 계약으로 완전히 모델링돼 있지 않다. 문자열 규칙만 추가하지 말고 기능 설명자와 실행기가 같은 자원 용어를 사용하도록 확장해야 한다.
29.5 도메인별 관리 대상 Task 사양
29.5.1 이동과 스테이션 복귀
| 항목 | setMoveTo |
returnToStation |
|---|---|---|
| 대상 | 등록 공간 ID·이름 또는 좌표 | 스테이션 공간·상태 증거 |
| 기본 정책 | ASYNC, movement, HIGH, 120초 | ASYNC, movement, HIGH, 120초 |
| 시작 전 | 대상 확인, 필요 시 실행 중인 청정 중지 | 이미 스테이션인지 확인 |
| 완료 | movement.arrived + 위치 안정 + 이동 정지 |
movement.stationCharging |
| 취소 | stopMovement |
stopMovement |
| 보상 동작 | stopMovement |
stopMovement |
| 주요 제약 | LLM, 배터리, AMR, 개인정보 보호, 지도 편집, 오류와 동시 이동 | 동일하나 안전 복귀 예외 존재 |
MovementTaskExecutor는 이동 전에 활성 청정을 멈추고 cleaning.stopped를 기다리는 전환 경로를 갖는다. 이는 “청정 중 이동 불가” 정책을 임의로 우회하는 예외가 아니다. 같은 Workflow 안에서 선행 물리 동작을 안전하게 정리한 뒤 이동하는 관리 전환이다.
현재 엄격 검증기가 허용하는 setMoveTo 키와 실행기가 실제로 인식하는 areaId, targetRoom, roomName 범위에 차이가 있다. 엄격 검증을 기본 활성화하기 전에 검증기와 표준 어댑터를 정합해야 한다.
29.5.2 청정
| 항목 | 사양 |
|---|---|
| 입력 | 동작, 모드·범위, 속도, AI와 선택 공간 |
| 기본 정책 | ASYNC, cleaning, CONTROL, 최대 1200초 |
| 완료 조건 | cleaning.started, cleaning.stopped, cleaning.stepComplete, cleaning.reportDone |
| 기본 완료 선택 | 중지 동작은 stopped, 기본 청정 시작은 stopped, 이동청정은 reportDone 중심 |
| 최소 실행 시간 | cleanMinTimeMs가 있으면 제한된 청정 시간 뒤 중지 가능 |
| 취소·보상 | 청정 중지 계약 |
| 이미 실행·정지 | 현재 상태와 공간이 맞으면 최신 완료 표시 생성 가능 |
청정 시작 응답을 완료로 볼지, 일정 시간 청정 후 중지를 완료로 볼지, 전체 이동청정 결과 보고까지 기다릴지는 Workflow 목적에 따라 completionTarget으로 구분한다.
29.5.3 LLM/TTS
| Task | 완료 | 취소 | 주의 |
|---|---|---|---|
| LLM 상태 제어 | 상태 콜백 | 상태 변경·중지 | 상태 갱신과 사용자 세션을 구분 |
| TTS 재생 | tts.playbackEnded |
stopTts |
재생 요청 응답만으로 완료하지 않음 |
| LLM 중지 | 중지·IDLE 증거 | 해당 없음 | 진행 중 물리 Task 재개와 연동 가능 |
TTS는 스피커를 사용하지만 현재 공통 speaker 자원 점유 계약이 없다. Security·이동과 동시 실행 가능한지, 사용자 음성 입력 중 재생을 허용할지는 제품 UX 정책으로 명시하고 기능 자원에 반영해야 한다.
29.5.4 바이탈사인과 외부 앱 세션
| 단계 | 사양 |
|---|---|
| 시작 | 런처 화면·앱 실행 후 app.sessionStarted 또는 UI 적용 증거 |
| 실행 중 | 카메라, 전면 화면과 외부 앱 세션 점유 |
| 완료 | 사용자가 측정을 완료해 app.sessionEnded 콜백 발생 |
| 취소 | 사용자 취소 또는 상위 취소로 앱 세션 종료 |
| 시간 초과 | 성공으로 처리하지 않고 세션 시간 초과·실패로 종료 |
| 상관관계 | completionKey 필수 |
바이탈사인은 화면을 띄운 순간 끝나는 단기 UI Task가 아니다. 측정 완료 또는 취소까지 이어지는 장기 세션이다. 후속 단계는 앱 세션의 최종 증거를 받은 뒤에만 시작한다.
29.5.5 보안
| 동작 | 완료 조건 | 자원·제약 |
|---|---|---|
| 시작 | security.started |
카메라, 이동과 Security 세션 점유. 스트리밍·Vital Sign과 충돌 |
| 일시정지 | security.paused |
기존 세션 제어이므로 항상 도달 가능해야 함 |
| 재개 | security.resumed |
저전력과 오류 상태 확인 |
| 중지 | security.stopped |
종료 제어는 자원 충돌 때문에 막히면 안 됨 |
| 순찰 완료 | security.patrolCompleted |
세션 종료인지 한 번의 순찰 완료인지 구분 |
Security 시작은 자신의 현재 Security 상태를 자원 스냅숏에서 제외해 자기 충돌을 피한다. 일시정지·재개·중지는 기존 세션 제어로 실행을 허용한다.
29.5.6 Welcome·Wakeup·Relax 상호작용
| 단계 | 완료 증거 |
|---|---|
| 세션 시작 | interaction.started |
| 목표 위치 도착 | interaction.arrived |
| 동작 시작·종료 | interaction.actionStarted, interaction.actionEnded |
| 복귀 | interaction.returning |
| 전체 종료 | interaction.completed |
interSchedule의 기본값은 ASYNC 실행, interaction 대기열, HIGH 우선순위, 1200초 제한이다. 완료 상태는 scheduleId를 키로 조회한다. InterScheduleManager에는 LLM 개입 정책으로 WAIT, RESTART, STOP이 정의돼 있으며 현재 기본값은 STOP이다.
STOP 정책에서도 relax 음원은 호출어 또는 LLM 세션이 시작되면 일시정지하고, 세션이 끝나면 재개하는 별도 흐름을 따른다. 단순히 예약 시각이 됐거나 TTS가 시작됐다는 이유로 전체 상호작용을 완료 처리하면 안 된다.
29.5.7 Vision, 회전과 스테이션 관찰
| Task | 요구 자원 | 완료·결과 | 현재 한계 |
|---|---|---|---|
observeVisionSemantics |
이동 기반부 + 카메라 | 최신 의미 관찰 결과 | 객체 방향·거리·추적은 별도 기능 필요 |
rotateInPlace |
이동 기반부 | movement.rotationCompleted |
이동 생명주기와 충돌 관리 필요 |
probeDockingSignal |
스테이션·AMR 관찰 | 현재 신호 스냅숏 | 신호를 따라 자동 이동하는 기능이 아님 |
getStationLocationEvidence |
지도·스테이션 제공자 | 증거 Bundle | 위치 재탐색 Workflow와 구분 |
관찰 Task가 COMPLETED라는 것은 센서 호출이 정상 종료됐다는 뜻일 수 있다. 원하는 객체를 찾았거나 스테이션 위치 변경을 확정했다는 뜻은 아니다. 결과 구조의 detected, 신뢰도, 최신성과 증거 품질을 다음 단계 조건에서 확인해야 한다.
29.6 Workflow에서 Task 단위 사양을 사용하는 방법
예를 들어 “안방으로 이동해 바이탈사인을 측정하고 끝나면 스테이션으로 복귀”는 단순히 세 Task를 나열한 것이 아니라, 서로 다른 세 완료 계약을 연결한 Workflow다.
중간에 사용자가 말을 걸면 단계 1 또는 단계 3은 일시정지·재개 대상이 될 수 있다. 단계 2는 외부 앱 세션 정책에 따라 음성 처리 허용 여부를 따로 정의해야 한다. 바이탈사인 화면이 열렸다고 단계 3을 시작하거나, LLM이 IDLE이 됐다는 이유만으로 바이탈사인 세션을 완료 처리하면 안 된다.
29.7 구현 상태와 보강 우선순위
| 우선순위 | 보강 항목 | 이유 |
|---|---|---|
| 1 | LLM·기기 정책 거절을 공통 실패 사유 계약으로 승격 | 실행 허용 뒤 발생한 거절 원인을 Planner와 UI가 이해해야 함 |
| 2 | voice_session, speaker, tilt_head 자원 용어 정의 |
음성·관찰·화면 Task의 경쟁을 구조화해야 함 |
| 3 | 엄격 검증기와 실행기의 표준 필드 정합 | 엄격 검증 기본 활성화 전 setMoveTo 등 정상 요청의 잘못된 거절 방지 |
| 4 | 장기 세션별 시작·종료·취소 행렬을 CI에서 검사 | Vital Sign, Security와 상호작용의 조기 완료 방지 |
| 5 | 일시정지·재개 생명주기를 TaskRecord와 이벤트에 명시 |
RUNNING과 실제 일시정지 상태의 차이를 모니터에 노출 |
| 6 | 기기 도메인 정책 스냅숏을 계획 컨텍스트와 실행 허용 단계에 투영 | 규칙 복제 없이 조기 거절 품질 향상 |
| 7 | 공통 자원 점유 계약 확대와 출시 인수 시험 | 카메라·화면·이동 외 자원 충돌 방지 |
보강의 핵심은 if (발화에 특정 단어가 있으면) 같은 규칙을 늘리는 것이 아니다. 기능이 요구하는 자원, 현재 기기 상태와 Task 완료 계약을 구조화해 상위 Planner와 DeviceAgent가 같은 용어와 계약을 사용하게 하는 것이다.
30. 기존 시스템 호환성과 점진적 전환 사양
TaskManager 도입은 기존 DeviceAgent 기능을 다른 구현으로 교체하는 작업이 아니다. 기존 PUI, IoT, 시스템 앱, Schedule과 Voice/LLM 호출이 사용하던 MainApi와 기기 도메인 구현을 유지하고, 관리가 필요한 요청만 TaskManager 생명주기에 편입하는 점진적 확장이다.
구조도의 두 실행 경로는 모두 같은 기존 기기 도메인에 도달한다. 차이는 기존 호출이 MainApi.executeMethod()와 executeMethodInternal()을 유지하는 반면, 관리 호출은 명시적 Task API 또는 forceTaskManager=true를 통해 실행 허용, 대기열과 생명주기 관리를 먼저 거친다는 점이다.
두 경로는 마지막에 같은 Movement, Cleaning, Schedule, Security, LLM/TTS와 Update 구현으로 합류한다. TaskManager는 기존 기능 로직을 복제하지 않고 실행 순서, 상태, 완료 증거와 취소 관리를 덧붙인다.
| 용어 | 한 줄 설명 |
|---|---|
| 기존 시스템 | TaskManager 도입 전부터 사용하던 MainApi, 기기 도메인 기능, 콜백과 호출 방식 |
| 호출자 | PUI, IoT, 앱, Schedule, Voice/Cloud처럼 DeviceAgent에 명령을 보내는 주체 |
| 관리 경로 | 요청을 Task로 등록해 순서, 상태, 완료와 취소를 TaskManager가 관리하는 실행 경로 |
| 선택 적용 | 모든 요청을 한꺼번에 바꾸지 않고 지정한 호출과 기능에만 TaskManager를 적용하는 방식 |
| 반환 계약 | 호출자가 언제 어떤 결과 필드를 받는지 정한 약속 |
| 점진적 전환 | 기존 기능을 유지한 채 검증된 기능부터 관리 경로로 옮기는 과정 |
| 원복 | 문제가 생겼을 때 해당 호출을 검증된 기존 경로로 되돌리는 절차 |
30.1 호환성 목표와 비목표
요약: 기존 기능을 유지하면서 필요한 경로부터 TaskManager 관리 대상으로 전환한다.
| 구분 | 목표 | 비목표 |
|---|---|---|
| 기존 호출자 | 수정하지 않은 호출자가 기존 경로와 반환 방식으로 계속 동작 | 첫 출시부터 모든 호출을 강제로 TaskManager 경로로 전환 |
| 기기 도메인 기능 | 같은 메서드가 같은 기기 도메인과 제품 정책을 사용 | 도메인 정책을 TaskManager에 복사해 우회 |
| 관리 경로 호출자 | 필요한 기능부터 Task·Workflow 생명주기를 선택 적용 | forceTaskManager를 붙여도 결과 형식과 시점이 완전히 같다고 가정 |
| 콜백 | 기존 콜백을 유지하며 Task 이벤트를 추가 발행 | 기존 콜백 수신자를 한 번에 제거 |
| 스케줄 | 제품 반복 스케줄과 TaskManager 지연 실행을 병존 | 기존 스케줄 DB를 자동 변환하거나 의미를 재해석 |
| SDK | 기존 원시 API와 타입 기반 AAR을 함께 운영 | 모든 시스템 앱의 동시 전환 |
| 원복 | 호출자 또는 시스템 속성 단위로 기존 경로 복귀 | 데이터와 앱을 되돌릴 수 없는 일괄 전환 |
호환성은 “컴파일된다”가 아니라 다음 네 수준으로 판정한다.
- 호출 호환성: 기존 메서드와 필드를 계속 보낼 수 있다.
- 동작 호환성: 같은 기기 도메인이 같은 물리 동작과 안전 정책을 수행한다.
- 관찰 호환성: 기존 콜백과 UI·IoT 상태 갱신이 유지된다.
- 운영 호환성: 배포, 재부팅 복원, 모니터링과 원복이 가능하다.
30.2 이중 실행 경로
요약: 기존 요청은 종전 경로로, 관리 대상 요청은 TaskManager 경로로 보내며 실제 기능은 같은 기기 도메인이 수행한다.
MainApi.executeMethod()의 호환 분기는 다음 순서를 따른다.
구조도의 분기 순서는 명시적 제어 API, forceTaskManager=true인 기존 메서드, 그 밖의 기존 메서드 순이다. 각 요청은 각각 TaskManager.handleControlMethod(), TaskManager.executeLegacy(), executeMethodInternal()로 전달된다.
소스 표현 빠른 해석
| 소스 표현 | 쉬운 한 줄 설명 | 실제 영향 |
|---|---|---|
MainApi.executeMethod() |
DeviceAgent로 들어온 명령이 가장 먼저 거치는 공통 접수 창구 | 여기서 기존 경로와 TaskManager 경로를 구분한다. |
TaskManager.handleControlMethod() |
Task 등록, 조회, 취소처럼 TaskManager 자체 명령을 처리하는 입구 | 일반 기기 기능과 Task 관리 명령을 섞지 않는다. |
executeMethodInternal() |
TaskManager 도입 전부터 사용하던 기존 기능 실행 경로 | 기존 호출자가 아무 설정을 바꾸지 않으면 이 경로를 계속 사용한다. |
forceTaskManager=true |
이 요청만 기존 즉시 실행 대신 Task로 관리하라는 표시 | 대기열, 상태 추적, 완료 확인과 취소가 적용될 수 있다. |
TaskManager.executeLegacy() |
기존 형식의 명령을 TaskManager가 이해할 수 있는 Task로 감싸는 연결부 | 호출 형식을 한 번에 바꾸지 않고도 점진적으로 관리 경로를 시험할 수 있다. |
runningManagedTask |
이미 TaskManager가 실행 중인 명령인지 기억하는 내부 재진입 방지 표식 | 기존 MainApi를 다시 호출해도 같은 명령이 Task로 중복 등록되는 것을 막는다. |
TaskPolicy |
기능별 실행 방식, 대기열, 우선순위와 시간 제한을 정한 실행 규칙 | 같은 메서드라도 어떤 순서와 방식으로 처리할지가 결정된다. |
TaskRecord |
접수된 작업의 ID, 상태, 결과와 실패 이유를 보관하는 실행 기록 | 모니터링, 취소, 콜백 상관관계와 장애 분석의 기준이 된다. |
소스 심볼은 현재 구현 위치를 설명하기 위한 근거다. 외부 호출자가 의존해야 하는 공개 계약은 제어 API, AAR 스키마와 콜백 계약이다. 내부 클래스 이름은 리팩터링 과정에서 바뀔 수 있다.
30.2.1 외부 MainApi 기존 경로
forceTaskManager가 없으면 기존executeMethodInternal()을 그대로 사용한다.- 기존 호출자의 즉시 반환, 오류 전달과 콜백 계약은 TaskManager 대기열 때문에 바뀌지 않는다.
- TaskManager 전체 활성화 상태와 무관하게 기존 원시 경로는 유지한다.
30.2.2 외부 MainApi 관리 경로
- 명시적
submitTask/submitWorkflow또는forceTaskManager=true요청만 관리 경로로 들어간다. TaskPolicy가DIRECT이면 기존 함수를 직접 호출하되 Task 결과를 기록한다.ASYNC와QUEUED_WAIT이면TaskRecord와 대기열을 만들고 기존 도메인 실행기를 호출한다.- 실행기가 다시
MainApi를 사용할 때runningManagedTask재진입 보호 장치가 대기열 중복 등록을 막는다.
30.2.3 내부 AppCmd 모듈 경로
DeviceAgent 내부 AppCmd에는 외부 MainApi와 다른 호환 분기가 있다.
| 조건 | 현재 동작 | 쉬운 설명 |
|---|---|---|
| Agent가 AMR 또는 UPDATE가 아님 | 기존 모듈 직접 전달 | 현재 자동 관리 대상은 두 내부 모듈로 제한된다. |
delayMillis > 0 |
기존 지연 전달 | 지연 메시지는 기존 Handler의 시간 의미를 보존한다. |
| 메서드 없음 | 기존 직접 전달 | Task로 식별할 수 없으므로 종전 경로를 유지한다. |
| 조회·센서·결과·콜백 | TaskIngressClassifier가 비Task로 분류해 직접 전달 |
상태 전달이나 콜백을 새 기기 동작 Task로 만들지 않는다. |
명령이지만 정책이 DIRECT |
직접 전달 | 빠른 조회와 즉시 결과의 반환 의미를 유지한다. |
명령이며 DIRECT가 아님 |
executeInternalModuleCommand() → executeLegacy() |
기존 모듈 명령을 대기열과 TaskRecord로 관리한다. |
| 이미 관리 대상 실행 내부 | runningManagedTask로 직접 전달 |
실행기가 기존 모듈을 호출할 때 Task가 중첩 생성되지 않는다. |
이 경로에서는 persist.sys.deviceagent.taskmanager.legacy_queue 기본값이 true이므로 조건을 만족하는 내부 명령이 자동으로 대기열에 들어갈 수 있다. 반면 외부 MainApi 원시 호출은 이 속성만으로 관리 경로에 들어가지 않으며 forceTaskManager=true가 필요하다.
30.2.4 TaskManagerClient AAR 경로
| AAR 호출 | 생성되는 요청 | 호환 의미 |
|---|---|---|
TaskSubmitRequest.toBundle() |
method=submitTask, forceTaskManager=true |
명시적으로 관리 대상 단일 Task 제출 |
TaskWorkflowRequest.toBundle() |
method=submitWorkflow, forceTaskManager=true |
명시적으로 관리 대상 Workflow 제출 |
| 조회·취소 API | TaskManager 제어 메서드 | 물리 기능이 아니라 Task 상태와 대기열을 제어 |
sendRaw(Bundle) |
호출자 Bundle을 복사해 그대로 전달 | 강제 실행 플래그를 자동으로 붙이지 않으므로 경로 선택은 호출자 책임 |
AAR은 모든 기존 호출을 자동 변환하는 프록시가 아니다. 타입 기반 요청 생성기는 관리 계약을 만들고, sendRaw()는 점진적 전환 중 아직 타입 기반 API가 없는 기존 계약을 보존한다.
forceTaskManager는 단순 로그 표시가 아니다. 요청을 Task 생명주기에 편입하고 반환 시점과 결과 구조를 바꿀 수 있는 호환성 경계 플래그다.
30.2.5 IoT·App·LLM Agent의 채널별 적용 방식
결론: MQTT 연결과 기존 명령을 일괄 교체하지 않는다. 기존 단일 명령은 그대로 두고, Task 생명주기가 필요한 요청만 선택적 관리 계약으로 확장한다.
TaskManager 도입으로 바뀌는 범위는 MQTT broker, topic, 인증, QoS와 재연결 같은 전송 계층 전체가 아니다. 바뀌는 부분은 명령 payload가 직접 실행인지 관리 대상 Task·Workflow인지 표현하는 응용 계약과, 관리 요청의 진행·완료를 돌려주는 결과 계약이다.
| 호출 경로 | 기존 호출 유지 | 관리가 필요한 단일 동작 | 여러 단계 Workflow | 현재 구현 경계 |
|---|---|---|---|---|
| 원격 App·IoT → MQTT | 기존 topic과 기능 payload를 그대로 전송 | 기존 request.method와 request.payload를 유지하고 선택적으로 request.task 추가 |
공통 submitWorkflow envelope와 subTasks[] 사용 |
단일 명령의 선택적 wrapping은 구현됨. MQTT JSON Workflow 배열 파서는 추가 필요 |
| 기기 내 System App | 기존 Binder·MainApi 원시 Bundle 유지 |
TaskManagerClient AAR의 TaskSubmitRequest 사용 |
AAR의 TaskWorkflowRequest 사용 |
타입 기반 생성기와 sendRaw() 호환 경로가 함께 존재 |
| LLM Agent·Cloud | 기존 원시 명령으로 추론 결과를 직접 실행하지 않음 | device_task_requests[]를 On-device Bridge가 submitTask로 변환 |
device_workflow_requests[]를 submitWorkflow로 변환 |
Cloud는 구조화된 요청을 생성하며, Bridge와 DeviceAgent 계약 버전 정합이 필요 |
| PUI·내부 이벤트 | 기존 도메인 직접 호출 유지 가능 | 제품이 상태 추적·취소를 요구하는 동작만 선택 적용 | 사전 정의된 제품 Workflow가 있을 때 사용 | 모든 버튼·센서·콜백을 Task로 올리면 안 됨 |
MQTT를 전부 바꾸지 않는 이유
MQTT의 기존 기능 payload는 이미 DeviceAgent 도메인 입력과 연결되어 있다. 이를 새 스키마로 일괄 치환하면 Topic parser, 응답 앱, 서버와 구버전 기기의 동시 배포 문제가 커진다. 현재 IotTaskManagerBridge는 다음 방식으로 호환성을 유지한다.
request.task 없음
-> 기존 parser가 만든 method와 payload 유지
-> 기존 MainApi 직접 실행
request.task 있음, managed 생략 또는 true
-> 기존 method를 taskMethod로 보존
-> method=submitTask, source=iot로 감쌈
-> payload는 그대로 두고 Task metadata만 추가
request.task.managed=false
-> 기존 직접 실행 유지
따라서 기존 MQTT 명령은 수정하지 않아도 계속 동작한다. TaskManager가 필요한 명령만 아래처럼 task 객체를 추가한다.
{
"correlationId": "move-bedroom-001",
"request": {
"method": "setMoveTo",
"payload": {
"positionId": "5"
},
"task": {
"managed": true,
"executionMode": "async",
"completionTarget": "movement.arrived"
}
}
}
priority, queueKey, timeoutMs, preemptPolicy까지 모든 값을 외부가 채울 필요는 없다. 생략된 값은 TaskPolicyRegistry의 메서드별 기본 정책으로 보강한다. 외부 입력값은 호출자 정책과 허용 범위로 다시 검증하며, 특히 EMERGENCY, 전체 대기열 교체와 임의 취소·보상 메서드는 그대로 신뢰하지 않는다.
복합 Workflow는 별도 계약으로 추가한다
여러 단계를 기존 단일 명령 Topic에 억지로 분산하면 서버 또는 App이 각 단계의 완료를 추측하고 다음 명령을 보내야 한다. 이 경우 TaskManager의 순서·취소·실패 전파 이점을 잃는다. 복합 실행은 하나의 submitWorkflow 요청으로 제출한다.
{
"correlationId": "clean-return-001",
"request": {
"method": "submitWorkflow",
"payload": {
"workflowName": "bedroom_clean_return",
"subTasks": [
{"taskMethod": "setMoveTo", "positionId": "5"},
{"taskMethod": "setAirCleanerOperation", "action": "1", "mode": "1"},
{"taskMethod": "returnToStation"}
]
}
}
}
이 형식은 기존 모든 MQTT Topic을 변경한다는 뜻이 아니다. submitWorkflow를 처리하는 공통 command parser 또는 전용 관리 Topic 하나를 추가하고, 기존 단일 명령 Topic은 유지하는 방식이 안전하다. 현재 MR6의 IotTaskManagerBridge는 단일 명령의 request.task 변환까지 구현되어 있으며, payload.subTasks[]를 ArrayList<Bundle>로 만드는 MQTT Workflow parser는 아직 구현 완료로 보면 안 된다.
응답과 이벤트의 호환 원칙
| 요청 종류 | 기존 응답 | 추가 관리 응답 | 호출자가 완료로 판단하는 기준 |
|---|---|---|---|
| 기존 직접 명령 | 기존 response topic·도메인 callback | 없음 | 기존 계약 유지 |
| 관리 단일 Task | 기존 기능 callback 유지 | accepted, taskId, STARTED/PROGRESS/COMPLETED/FAILED/CANCELLED |
accepted가 아니라 terminal event 또는 상태 조회 |
| 관리 Workflow | 기존 단계별 도메인 callback 유지 | 부모 Workflow와 단계별 Task event | 부모 Workflow terminal state |
기존 callback을 즉시 제거하면 구버전 App과 IoT 서버가 상태를 잃는다. 전환 기간에는 기존 callback과 Task event를 함께 발행하되, requestId, traceId, correlationId로 같은 실행을 묶고 수신자는 중복 반영하지 않아야 한다.
채널 전환 순서
- 기존 MQTT·App 명령과 응답을 기준선으로 고정한다.
- 취소·진행률·물리 완료 추적이 필요한 메서드 하나를 선택한다.
- IoT는
request.task, System App은 AAR, LLM은 구조화된 device request로 같은 Task 의미를 만든다. - 기존 callback과 Task event가 같은 물리 실행을 가리키는지 확인한다.
- 단일 Task가 안정화된 뒤 공통
submitWorkflowingress를 추가한다. - 호출자×메서드 단위로 확대하며 기존 direct 경로는 원복 수단으로 유지한다.
이 구조에서 호출 채널은 서로 달라도 TaskManager가 받는 최종 계약은 동일하다. 반대로 센서 update, heartbeat, 조회 결과와 단순 상태 동기화는 실행 생명주기가 아니므로 기존 메시지 경로에 남긴다.
30.2.6 기존 direct 명령과 관리 Task의 동시성
현재는 관리 Task끼리의 순서는 TaskManager가 통제하지만, 비관리 direct 명령은 대기열 밖에서 실행된다. 두 경로는 기존 DeviceAgent 도메인 정책에서 다시 만나므로 물리 안전 제한은 공유하지만, 실행 순서와 Task 상태까지 자동으로 정합되는 것은 아니다.
현재 구현에서 보장되는 범위
| 경쟁 조합 | 현재 조정 담당 | 보장되는 것 | 현재 한계 |
|---|---|---|---|
| 관리 Task ↔ 관리 Task | TaskManager Queue·Priority·Preemption·Domain Resource Policy | 같은 대기열의 순서, 관리 작업 취소, 일부 자원 충돌 거절 | 자원 선언이 없는 기능은 충돌을 모두 알 수 없음 |
| 기존 direct ↔ 기존 direct | StateManager, CmdPolicyManager와 각 도메인 Manager |
제품 상태, 배터리, 오류, 이동·청정 중복 등 기존 제품 정책 | 공통 Task ID·대기열·진행 상태 없음 |
| 관리 Task ↔ 기존 direct | 기존 도메인 상태와 물리 정책 | 금지된 동작의 거절 또는 도메인 고유 정지·전환 | direct 요청은 TaskManager Queue와 TaskRecord에 보이지 않으므로 전역 순서·선점 사유·상태 정합이 불완전 |
| 관리 실행 내부의 기존 API 재호출 | runningManagedTask |
같은 실행을 Task로 다시 감싸는 재진입 방지 | ThreadLocal 표식이므로 다른 스레드의 direct 명령을 막는 전역 잠금이 아님 |
| DeviceAgent 내부 AMR·UPDATE 명령 | AppCmd.executeThroughTaskManager() 선택 연결 |
조회·콜백이 아닌 비DIRECT 명령 일부를 기존 형식 그대로 대기열에 편입 | 외부 MainApi·MQTT direct 요청 전체에 적용되는 구조는 아님 |
예를 들어 관리 Task가 이동 중일 때 기존 App이 direct setMoveTo를 보내면, 후속 명령은 기존 CmdPolicyManager.setMoveTo()의 is_moving 검사에서 거절될 수 있다. 이는 물리적으로 두 이동을 동시에 실행하지 않게 하지만, 거절된 direct 요청을 TaskManager가 대기시키거나 원래 이동 Task의 선점 사유로 기록한 것은 아니다.
반대로 PUI 정지나 복귀가 기존 경로에서 현재 동작을 중단할 수 있다. 해당 도메인의 중단 callback이 TaskCompletionStateStore와 연결된 기능은 관리 Task가 취소·실패로 닫힐 수 있지만, 모든 도메인에서 원인과 Task ID가 연결된다고 가정하면 안 된다. 연결이 없는 기능은 관리 Task가 물리 중단을 모르고 시간 초과까지 남을 수 있다.
호환성을 유지하는 공통 동시성 경계
기존 direct 호출을 모두 공개 단일 Task로 바꾸지 않고도 동시성을 맞추려면, TaskManager와 기존 경로 아래에 공통 실행권 조정 경계가 필요하다.
기존 direct 요청 ─┐
├─ 실행 분류 ─ 공통 도메인 실행권/자원 점유 ─ 기존 DeviceAgent 정책 ─ 실제 동작
관리 Task 요청 ───┘ │
└─ 시작·중단·완료 증거를 원 요청에 귀속
이 경계는 자연어 의미를 추론하는 규칙이 아니다. TaskPolicyRegistry, 기능 계약과 requiredResources에 선언된 실행 특성을 사용해 결정적으로 동작한다.
| 요청 성격 | 권장 처리 | 기존 호환 의미 |
|---|---|---|
| 조회·센서·heartbeat·상태 callback | 기존 direct 유지, 실행권 미점유 | 응답 시점과 기존 상태 전달 유지 |
| 짧고 멱등적인 설정 | 기존 direct 유지 가능, 충돌 자원만 공통 검사 | 불필요한 Task 이벤트와 대기 지연 방지 |
| 이동·청정·보안·외부 앱 세션처럼 장기 자원 점유 | 명시 Task 또는 검증된 메서드만 내부 단일 Task로 승격 | 외부 payload는 유지하되 내부 실행 순서와 완료를 관리 |
| 기존 PUI 정지·사용자 취소 | 즉시 허용하되 점유 중인 관리 Task도 CANCELLED로 종료 |
사용자의 직접 통제권을 유지하면서 고립 Task 방지 |
| 오류·저전력·긴급 복귀 | 안전 우선 선점 후 기존 Task를 구조화된 사유로 종료 | 안전 정책이 Task 우선순위보다 항상 우선 |
| 일반 App·IoT의 충돌 명령 | 실행권이 비면 수행, 점유 중이면 busy 거절 또는 선택적 Task 대기 | 기존 명령이 관리 Workflow를 조용히 덮어쓰지 않게 함 |
장기 direct 동작의 실행권을 물리 완료까지 유지하려면 결국 시작·중단·완료 callback과 연결된 내부 기록이 필요하다. 따라서 이동·청정 같은 메서드는 검증이 끝난 순서대로 외부 응답 형식은 유지하면서 내부적으로 단일 Task로 승격하는 편이 단순한 잠금보다 안정적이다. 반면 조회와 상태 update까지 Task로 승격하면 대기열과 이벤트만 오염되므로 그대로 direct로 둔다.
충돌 결과의 일관된 귀속
동시성 조정 결과는 물리 동작과 관리 상태가 함께 바뀌어야 한다.
| 실제 상황 | 물리 처리 | 관리 Task 처리 | 권장 사유 |
|---|---|---|---|
| 사용자가 PUI로 정지 | 기존 도메인 정지 수행 | 관련 실행 Task 취소 | user_cancelled 또는 pui_cancelled |
| 안전 정책이 강제 복귀 | 현재 동작 중단 후 복귀 | 기존 Task 실패·선점, 복귀 Task 추적 | safety_preempted, 세부 오류 코드 |
| 일반 direct 명령이 관리 자원과 충돌 | 실행하지 않음 | 기존 Task 유지 | device_busy, 점유 자원과 Task ID |
| 같은 목적의 중복 요청 | 물리 재실행 없음 | 기존 실행 상태 반환 또는 요청 연결 | already_running |
| 허용된 우선순위 선점 | 기존 도메인 취소 확인 후 새 실행 | 이전 Task terminal 후 새 Task 시작 | preempted_by_request |
단순히 CmdPolicyManager가 POLICY_NOT_ALLOWED를 반환하는 것으로 끝내면 호출자는 “왜 안 됐는지”, TaskManager는 “기존 작업이 계속 유효한지”를 알 수 없다. 도메인 정책 결과를 errorCode, reason, 점유 자원과 관련 taskId로 연결해야 동시성 호환이 완성된다.
단계적 적용
- 기존·관리 경로의 동시 실행 조합을 로그로만 관찰한다.
- 이동·청정·보안·화면/카메라 세션의 자원 소유권과 사용자 취소 결과를 표준화한다.
- 충돌 가능 direct 명령에 공통 실행권 검사를 적용하되 기존 응답 형식은 유지한다.
- 검증된 장기 메서드만 내부 단일 Task 승격 대상으로 확대한다.
- PUI·오류·저전력 선점이 기존 관리 Task를 올바른 terminal 상태로 닫는지 실기기에서 검증한다.
- 호출자×메서드 단위 회귀가 끝날 때까지 기존 direct 원복 경로를 유지한다.
30.3 호환성 표면
요약: API 이름뿐 아니라 입력값, 응답 시점, 콜백, 저장소, SDK와 배포 방식도 호환성 검토 대상이다.
| 검토 영역 | 기존 동작 | 관리 경로에서 추가되는 동작 | 호환 조건 |
|---|---|---|---|
| 진입 API | 원시 method 기반 MainApi |
제어 API와 Task·Workflow 요청 구조 | 기존 경로를 제거하지 않음 |
| 메서드 | 기존 DeviceAgent 메서드 | 표준 taskMethod와 별칭 |
실제 기기 도메인 수행 주체가 같아야 함 |
| 필드 | 기존 Bundle 키 | 표준 키와 허용 별칭 | 어댑터에 명시된 키만 호환 |
| 반환 시점 | 메서드별 기존 즉시·비동기 응답 | DIRECT, ASYNC, QUEUED_WAIT에 따라 달라짐 | 호출자가 기대하는 시점을 전환 전에 검증 |
| 반환 구조 | 기존 outdata |
Task ID, 상태, 실패 사유와 중첩 결과 | 신규 필드는 추가 방식으로 제공하고 기존 필수 필드는 유지 |
| 콜백 | 기기 도메인 고유 콜백 | Task 진행·최종 이벤트 추가 | 기존 수신자를 유지하고 이중 발행 허용 |
| 정책 | CmdPolicyManager, StateManager |
Task 실행 허용, 자원과 선점 사전 검사 | 최종 기기 도메인 정책을 우회하지 않음 |
| 스케줄 | 제품 스케줄 DB | TaskManager 지연 예약 저장소 | 저장소와 반복 의미를 혼합하지 않음 |
| IPC·SDK | AIDL과 원시 Bundle | TaskManagerClient AAR 타입 기반 진입점 |
스키마·버전과 원시 전송 경로 유지 |
| 배포 | 플랫폼 서명 시스템 앱 | 같은 프로세스·권한의 Core와 AAR | 기존 플랫폼 인증서와 권한 유지 |
| 모니터 | 기존 제품 상태와 UI | Task, 대기열과 Workflow 이벤트 | 모니터 상태가 실제 실행 상태를 임의로 만들지 않음 |
30.4 그대로 보존해야 하는 동작
요약: TaskManager를 사용해도 실제 기능 주체, 안전 정책, 기존 콜백과 제품 스케줄의 의미는 유지해야 한다.
다음은 TaskManager 도입 전후에 바뀌면 안 되는 호환 불변 조건이다.
- 같은 요청은 Movement, Cleaning, Schedule, Security 등 기존 수행 주체가 처리한다.
- 기존 PUI, IoT와 시스템 앱의 원시 메서드는 선택 적용 전까지 기존 경로를 사용한다.
- 기존 기기 도메인 콜백과 상태 갱신은 계속 발행된다.
- LLM, 배터리, AMR, 개인정보 보호, 오류와 주 상태 제한은 기존 기기 도메인이 최종 판정한다.
- 같은 기기 동작이 기존 경로와 관리 경로에서 중복 실행되지 않는다.
- TaskManager가 비활성화돼도 기존 핵심 기능은 원시 경로로 수행할 수 있어야 한다.
- 기존 제품 스케줄의 등록, 조회, 실행 의미와 DB 소유권은 유지한다.
- 시스템 앱 패키지, UID, 서명 권한과 플랫폼 인증서 관계를 유지한다.
30.5 선택 적용 후 달라질 수 있는 동작
요약: 같은 기능도 TaskManager를 거치면 “접수”와 “실제 완료”의 응답 시점과 결과 형식이 달라질 수 있다.
TaskManager 경로는 실행 기능은 같지만 호출 의미까지 완전히 투명하지는 않다.
| 실행 방식 | 호출자가 받는 시점 | 의미 | 기존 호출자 전환 시 위험 |
|---|---|---|---|
DIRECT |
기존 메서드 반환 직후 | 기존 결과를 Task 요약과 함께 반환 | 중첩 결과와 추가 필드 파싱 확인 필요 |
ASYNC |
실행 허용과 TaskRecord 생성 직후 |
물리 완료 전 접수 상태 | 기존 호출자가 응답을 완료로 오해할 수 있음 |
QUEUED_WAIT |
최종 상태 또는 시간 초과 후 | 실제 완료 증거를 기다림 | 기존 UI 스레드나 Binder 시간 초과 위험 |
같은 이동 명령의 호출 차이
아래 예시는 반환 의미를 설명하기 위한 개념 예시다. 실제 필드는 호출자 계약과 출시 스키마를 따른다.
기존 호출
{
"method": "setMoveTo",
"positionId": "5",
"positionName": "안방"
}
기존 이동 경로는 MainApi가 이동 도메인에 명령을 전달하고 기존 메서드 결과를 반환한 뒤, 기존 이동 콜백으로 도착 상태를 알리는 계약을 그대로 유지한다.
TaskManager 선택 호출
{
"method": "submitTask",
"forceTaskManager": true,
"taskMethod": "setMoveTo",
"source": "APP",
"requestId": "move-bedroom-001",
"positionId": "5",
"positionName": "안방",
"executionMode": "async",
"completionTarget": "movement.arrived"
}
{
"accepted": true,
"taskId": "task-...",
"taskState": "PENDING",
"message": "작업이 접수됨"
}
이 응답의 accepted=true는 안방 도착을 뜻하지 않는다. 이동 콜백이 movement.arrived 증거로 연결되고 Task가 COMPLETED가 돼야 실제 완료다. 기존 호출자는 종전 콜백을 계속 받을 수 있고, 관리 경로 호출자는 Task 이벤트 또는 getTaskStatus를 추가로 사용할 수 있다.
따라서 호출자별 전환 전에 다음을 명시한다.
- 기존 호출자가 접수 응답을 기다리는지 실제 완료를 기다리는지
- 동기 호출 시간 제한과 UI 스레드 사용 여부
- 기존
outdata에서 반드시 읽는 키 - 콜백을 별도로 기다리는지
- 중복 재시도가 기기 동작을 다시 일으킬 가능성
30.6 메서드·필드 별칭 계약
요약: 메서드·필드 별칭은 등록된 항목에만 적용되며 모든 과거 입력을 자동으로 호환하지 않는다.
별칭 처리는 기존 요청 데이터를 모두 자동 수용하는 범용 기능이 아니다. TaskMethodAliasResolver, TaskFields와 실행기 어댑터에 등록된 범위만 계약이다.
| 소스 표현 | 쉬운 한 줄 설명 | 호환성에서 확인할 점 |
|---|---|---|
TaskMethodAliasResolver |
과거 기능 이름을 현재 표준 기능 이름으로 바꿔 주는 이름 변환기 | 등록되지 않은 이름은 자동으로 추정하지 않는다. |
TaskFields |
여러 모듈이 함께 사용하는 Task 필드 이름을 모아 둔 공통 정의 | 호출자와 실행기가 같은 필드를 쓰는지 확인한다. |
| 실행기 어댑터 | 표준 Task 입력을 기존 기능이 이해하는 입력으로 바꾸는 연결 코드 | 변환 과정에서 값이 빠지거나 임의 기본값이 생기면 안 된다. |
queue / queueKey |
작업을 어느 실행 대기열에서 처리할지 지정하는 필드 | 클라이언트가 쓰는 이름과 Core가 읽는 이름을 하나로 맞춰야 한다. |
| 엄격한 입력 검증 | 정의되지 않은 필드를 오류로 차단하는 검사 방식 | 기존 호출자의 필드를 조사하지 않고 켜면 정상 요청도 거절될 수 있다. |
| 호출 필드 계약 확인 | 실제 호출자가 보내는 필드 이름과 값의 전체 목록을 확인하는 작업 | 문서에 없는 기존 입력까지 전환 전에 확인한다. |
| 기준 요청 회귀 시험 | 현재 정상 동작하는 대표 요청을 고정해 변경 전후 결과를 비교하는 검사 | 별칭이나 검증기 변경으로 생기는 회귀를 자동으로 찾는다. |
현재 대표 호환 범위:
- 청정 시작·중지·일시정지·재개와 복귀 별칭을 표준 청정 메서드로 정규화한다.
- schedule 식별자는
scheduleId,scheduleid,schedule_id를 일부 경로에서 수용한다. - 활성·대기열 필드는
isActive/is_active,taskQueue/queue를 일부 어댑터가 수용한다. - 결과에는 Task, 실패 사유와 Cloud 상관관계의 camelCase·snake_case 별칭을 함께 기록하는 경로가 있다.
현재 알려진 정합 공백:
TaskManagerClient요청 생성기는queue를 쓰는 반면 정책 변경값은queueKey를 읽는 경로가 있다.setMoveTo의 엄격 검증 허용 키와 실행기가 읽는areaId,targetRoom,roomName범위가 완전히 같지 않다.- 모든 기존 Bundle 키가 표준 스키마 별칭으로 등록된 것은 아니다.
따라서 엄격한 입력 검증을 기본 활성화하기 전에 메서드별 호출 필드 계약 확인과 기준 요청 회귀 시험을 수행해야 한다. 현재 기본값을 false로 유지하는 것은 기존의 유연한 요청이 갑자기 거절되는 상황을 막기 위한 호환 장치다.
30.7 콜백과 이벤트 호환
요약: 기존 콜백은 유지하고 TaskManager 이벤트로 진행률과 완료 상태를 추가한다.
관리 대상 Task는 기존 콜백을 대체하지 않고 완료 증거로 사용한다.
기존 PUI·IoT·시스템 콜백은 유지한다. 관리 대상 Task와 연결된 콜백만 CompletionBridge가 TaskCompletionStateStore와 Task 진행·최종 이벤트로 변환한다.
| 소스 표현 | 쉬운 한 줄 설명 | 실제 영향 |
|---|---|---|
CompletionBridge |
기존 기능 콜백을 Task 완료 증거로 연결하는 변환 지점 | 기존 기능 코드를 다시 만들지 않고 Task 상태를 닫을 수 있다. |
TaskCompletionStateStore |
가장 최근의 실제 완료·취소·실패 증거를 보관하는 저장소 | 오래된 콜백과 현재 Task의 콜백을 구분하는 기준이 된다. |
| 상관관계 필드 | 콜백이 어느 Task와 Workflow 단계의 결과인지 알려 주는 식별자 | 여러 작업이 동시에 수행돼도 결과가 다른 Task에 붙는 것을 막는다. |
| 최종 이벤트 | 작업이 완료·실패·취소돼 더 이상 진행되지 않음을 알리는 마지막 이벤트 | 다음 Workflow 단계를 시작하거나 전체 흐름을 종료하는 기준이다. |
| 멱등 처리 | 같은 콜백이 여러 번 와도 결과를 한 번만 반영하는 처리 방식 | 통신 재전송 때문에 완료 처리나 후속 동작이 중복되는 것을 막는다. |
Task 이벤트 전달 범위
TaskManager 내부 이벤트와 시스템 앱이 받는 모듈 콜백의 범위는 같지 않다.
| 이벤트 조건 | 내부 TaskEventListener |
AppCmd.sendModuleCallback_main() |
AAR onTaskEvent() 관찰 가능성 |
|---|---|---|---|
| non-INTERNAL source Task | 전달 | 전달 | 높음 |
| workflow parent/step | 전달 | 전달 | 높음 |
| INTERNAL 단일 Task의 STARTED/COMPLETED | 전달 | 기본 미전달 | 낮음. 상태 조회 또는 모니터 필요 |
| INTERNAL 단일 Task의 FAILED/TIMEOUT/CANCELLED | 전달 | 전달 | 높음 |
| 기존 기기 도메인 고유 콜백 | 기존 수신자에 전달 | 콜백별 기존 경로 | Task 이벤트와 별도 계약 |
TaskManagerClientCallback.onTaskEvent()는 DeviceControlProxy의 모듈 콜백을 받는다. 따라서 내부 수신자가 본 모든 이벤트가 AAR 클라이언트에도 전달된다고 가정하면 안 된다. 호출자별 관찰 요구에 따라 모듈 콜백, getTaskStatus, 모니터 이벤트 중 어느 경로를 사용할지 계약해야 한다.
호환 규칙:
- 기존 콜백 수신자를 유지한 상태에서 Task 이벤트를 추가 발행한다.
- 콜백의 기능 의미를 TaskManager에서 다시 추정하지 않는다.
- Task 이벤트에는
taskId, Workflow·단계 상관관계와 최신 시각을 추가한다. - 같은 콜백이 재전송돼도 최종 이벤트는 멱등하게 처리한다.
- Task Monitor가 콜백을 받지 못해도 기존 기능 상태를 덮어쓰지 않는다.
- 기존 콜백 제거는 모든 수신자의 전환과 원복 검증 이후 별도 출시에서 수행한다.
30.8 제품 스케줄과 저장소 호환
요약: 반복 제품 일정과 “30분 뒤 한 번 실행”하는 Task 예약은 서로 다른 기능과 저장소로 유지한다.
제품 반복 스케줄과 TaskManager 지연 실행은 저장 주체와 의미가 다르다.
| 구분 | 기존 제품 스케줄 | TaskManager 지연 예약 |
|---|---|---|
| 목적 | Welcome, Wakeup, 청정 같은 반복 생활 일정 | “30분 뒤 한 번 실행” 같은 단발 Task |
| 소유자 | Schedule 도메인 | TaskManager 예약 실행기 |
| 저장소 | 제품 스케줄 DB | taskmanager_scheduled_tasks.json |
| 실행 | 제품 시작 조건과 상호작용 정책 | 실행 시각에 최신 상태를 확인한 뒤 Task·Workflow 제출 |
| 전환 | 기존 기록 유지 | 기존 DB를 자동 복사하지 않음 |
기존 스케줄 기록을 TaskManager 기록으로 묵시 변환하거나, 제품 반복 일정을 단발 Task로 재해석하면 안 된다. 상위 Planner가 제품 스케줄을 만들더라도 기존 Schedule 도메인 메서드를 관리 대상 Task로 호출하며, 스케줄 데이터의 소유권은 그대로 유지한다.
30.9 AAR, Binder와 시스템 앱 호환
요약: 기존 앱은 종전 호출을 유지할 수 있고 신규 앱은 AAR을 사용할 수 있지만, 기기 서명과 권한 조건은 동일하게 적용된다.
TaskManagerClient AAR은 기존 DeviceAgent 기능을 다른 프로세스로 옮기는 SDK가 아니다. 기존 AIDL·Binder 경계 위에 타입 기반 Task API를 제공하는 진입점이다.
| 소스 표현 | 쉬운 한 줄 설명 | 기존 시스템과의 관계 |
|---|---|---|
TaskManagerClient AAR |
다른 시스템 앱이 TaskManager를 일정한 방식으로 호출하도록 제공하는 Android 라이브러리 | 앱마다 제각각 Bundle을 만드는 코드를 줄이되 기존 호출을 즉시 없애지는 않는다. |
| Binder/AIDL | Android 프로세스 사이에서 DeviceAgent API를 호출하는 통신 통로 | TaskManager를 도입해도 기존 프로세스와 권한 경계는 유지된다. |
| 타입 기반 요청 생성기 | 메서드와 필수 필드를 코드에서 명확하게 구성하는 호출 도구 | 잘못된 문자열과 누락 필드를 호출 단계에서 줄인다. |
sendRaw(Bundle) |
기존 Bundle 형식을 그대로 보낼 수 있는 호환용 우회 입구 | 아직 AAR로 감싸지 않은 기능도 단계적으로 옮길 수 있다. |
| 계약 버전 | 클라이언트와 DeviceAgent가 이해하는 API 계약의 버전 | 서로 다른 APK 조합에서 지원 여부를 명확히 판단한다. |
| 플랫폼 인증서 | 특권 앱이 서명 권한과 동일 UID 관계를 유지하는 데 필요한 제품 서명 | 디버그 서명 APK를 넣으면 권한 오류나 부팅 문제가 생길 수 있다. |
- 기존 앱은 원시 Bundle 호출을 유지할 수 있다.
- 신규 앱은 타입 기반 요청 생성기로 Task·Workflow·예약·제어 API를 사용할 수 있다.
sendRaw(Bundle)는 아직 타입 기반 API가 없는 메서드의 점진 전환 경로다.- AAR 계약 버전과 지원 메서드 목록은 DeviceAgent 출시 형상과 함께 관리한다.
- 클라이언트 AAR과 DeviceAgent APK의 갱신 순서가 달라도 지원하지 않는 계약은 명시적으로 거절해야 한다.
- 플랫폼 서명 특권 앱의 패키지, UID와 서명 권한 조건은 TaskManager 도입으로 완화되지 않는다.
- 실기기 교체 시
apksigner verify --print-certs로 기존 APK와 신규 APK 인증서를 비교하고, 디버그 인증서 APK를/system/priv-app에 배포하지 않는다.
30.10 단계적 전환
요약: 전체 기능을 한 번에 바꾸지 않고 호출자와 기능 단위로 전환하고 검증한 뒤 확대한다.
| 단계 | 적용 범위 | 완료 기준 |
|---|---|---|
| 0 | 호출자·메서드·필드·콜백 계약의 기준선 고정 | 기존 호출, 응답, 콜백과 물리 동작 증거 확보 |
| 1 | 조회·상태·제어 API를 추가 방식으로 노출 | 기존 원시 호출 회귀 없음 |
| 2 | 메서드와 호출자 단위로 forceTaskManager 선택 적용 |
응답 시점, 중복 전달과 기기 도메인 결과 검증 |
| 3 | 완료·취소 콜백을 Task 생명주기에 연결 | 조기 완료와 고립 Task 없음 |
| 4 | 시스템 앱별 타입 기반 AAR 전환 | 원시 경로와 버전 불일치 검증 |
| 5 | 검증된 메서드만 관리 경로 기본 후보로 승격 | 여러 요청 출처 회귀, 재부팅과 장기 안정성 통과 |
| 6 | 엄격한 입력 검증 확대 | 호출 필드 계약 확인과 기준 요청 회귀 시험 100% 통과 |
일괄 전환보다 호출자 x 메서드 x 실행 방식 단위 허용 목록이 안전하다. 예를 들어 Cloud Workflow의 setMoveTo만 먼저 관리 경로로 전환하고 PUI 단일 이동은 기존 경로를 유지할 수 있다.
30.11 원복 사양
요약: 문제가 생기면 전체 APK를 되돌리기 전에 해당 호출이나 관리 기능만 기존 경로로 원복할 수 있어야 한다.
| 문제 | 원복 수단 | 영향 범위 |
|---|---|---|
| 특정 호출자의 관리 경로 오동작 | forceTaskManager 제거 |
해당 요청만 기존 경로 복귀 |
| 기존 메서드의 대기열 감싸기 문제 | persist.sys.deviceagent.taskmanager.legacy_queue=false |
기존 연결부를 직접 실행으로 전환 |
| 강제하지 않은 Task API 문제 | persist.sys.deviceagent.taskmanager.enable=false |
강제 실행이 없는 submitTask·Workflow 차단, 기존 원시 경로 유지 |
| 강제 실행·AAR 요청 문제 | 호출자에서 타입 기반 제출 중단 또는 강제 플래그 제거 | 현재 활성화 속성만으로는 차단되지 않음 |
| 엄격한 스키마의 잘못된 거절 | 엄격 검증 속성·요청 해제 | 유연한 호환 모드로 복귀 |
| 클라이언트 AAR 불일치 | 원시 Bundle 경로 또는 이전 AAR | 해당 시스템 앱 |
| APK 출시 형상 문제 | 같은 플랫폼 인증서로 서명된 검증 APK 복원 | DeviceAgent 또는 시스템 앱 출시 형상 |
현재 TaskManager.isEnabled()는 forceTaskManager=true이면 활성화 속성보다 강제 실행을 우선한다. TaskSubmitRequest와 TaskWorkflowRequest도 강제 실행 플래그를 자동으로 추가한다. 따라서 persist.sys.deviceagent.taskmanager.enable=false는 모든 요청을 차단하는 전역 중지 스위치가 아니다.
강제 요청까지 즉시 차단해야 한다면 신뢰된 호출자별 기능 플래그나 DeviceAgent의 별도 긴급 실행 차단 장치가 필요하다.
원복은 설정만 바꾸는 절차로 끝나지 않는다. 실행 중인 대기열과 Task의 취소 또는 종료 대기, 콜백 이중 발행 정리, 예약 영속성 처리와 재부팅 후 상태 정합까지 정의해야 한다.
30.12 호환성 인수 기준표
요약: 빌드뿐 아니라 기존 호출, 실기기 동작, 콜백, 재부팅과 원복의 전후 결과를 비교해야 호환 완료로 본다.
각 전환 메서드는 다음 항목을 기존 경로와 관리 경로에서 대조한다.
| 검증 축 | 질문 | 필수 증거 |
|---|---|---|
| 호출자 | PUI, IOT, APP, VOICE/CLOUD 중 누가 호출하는가 | 호출자별 요청 추적 정보 |
| 요청 전달 | 같은 입력이 같은 기기 도메인에 한 번만 도달하는가 | 도메인 진입 로그와 requestId |
| 물리 동작 | 실제 동작과 안전 제한이 동일한가 | 기기 콜백, 상태, 영상 또는 센서 증거 |
| 반환 | 반환 시점과 필수 필드가 호출자 기대와 맞는가 | 기존·관리 경로 응답 비교 |
| 콜백 | 기존 콜백과 Task 이벤트가 필요한 모든 수신자에게 도달하는가 | 이중 이벤트 추적 정보 |
| 실패 | 기존 오류가 구조화된 실패 사유로 보존되는가 | 오류·실패 사유 변환표 |
| 취소 | 취소 요청이 실제 도메인 중지와 최종 상태로 닫히는가 | 취소 명령과 중지 증거 |
| 재시도 | 네트워크·시간 초과 재시도가 중복 동작을 만들지 않는가 | 같은 requestId 재제출 시험 |
| 스케줄 | 기존 제품 일정과 지연 Task가 서로 오염되지 않는가 | DB·저장소 스냅숏과 실행 시각 로그 |
| 재부팅 | 대기·실행·예약 상태가 최신 기기 상태와 정합되는가 | 재부팅 복구 추적 정보 |
| 배포 | 패키지, 소유자·권한, SELinux와 인증서가 맞는가 | APK 해시와 인증서 비교 |
| 원복 | 관리 경로를 끈 뒤 기존 기능이 즉시 복구되는가 | 원복 훈련 결과 |
최소 회귀 세트는 PUI, IoT/MQTT, Launcher·시스템 앱, 제품 Schedule과 Voice/LLM을 모두 포함해야 한다. JVM 시험이나 APK 빌드 통과만으로 기존 시스템 호환을 확정하지 않는다.
30.13 현재 남은 호환성 위험
요약: 기본 이중 경로는 마련됐지만 필드 이름, 응답 해석, 이벤트 중복, 버전 조합과 실기기 원복 검증은 아직 완료되지 않았다.
| 위험 | 소스에서 확인한 현재 상태 | 영향 | 필요한 보강 |
|---|---|---|---|
queue / queueKey 불일치 |
AAR 요청 생성기는 queue, TaskPolicyRegistry.resolve()는 queueKey 변경값을 읽음 |
호출자가 지정한 대기열이 무시될 수 있음 | 진입점 정규화와 양쪽 계약 시험 |
| 부분 별칭 | TaskMethodAliasResolver는 현재 청정 별칭 중심 |
다른 기존 이름은 자동 변환되지 않음 | 메서드별 별칭 목록과 폐기 계획 |
| 엄격 스키마 불일치 | 검증기와 실행기가 읽는 이동·스케줄 필드 범위가 다름 | 엄격 검증에서 정상 기존 요청을 잘못 거절 | 호출 필드 계약 확인 후 스키마·실행기 단일 정의 |
| 진입 분류 이름 추정 | 분류기가 result, sensor, callback, schedule 같은 메서드 표면을 사용 |
이름이 겹치는 신규 명령이 비Task로 분류될 수 있음 | 명시적 signalType 계약과 메서드 기준 시험 |
| 내부 적용 범위 제한 | AppCmd 자동 관리가 AMR·UPDATE와 지연 없는 요청에 한정 | IoT 또는 지연 모듈은 같은 방식으로 관리되지 않음 | 모듈별 의도 범위 확정과 인수 시험 |
| 콜백 가시성 차이 | INTERNAL 성공 이벤트는 내부 수신자에게 보이나 모듈 콜백은 기본 미발행 | AAR UI가 진행·완료를 놓칠 수 있음 | 호출자별 이벤트 구독·상태 조회 계약 |
| ASYNC 의미 변경 | 접수 응답이 물리 완료보다 먼저 반환 | 기존 호출자가 조기 성공 처리 가능 | 응답 비교와 콜백 전환 시험 |
| 활성화 속성 오해 | forceTaskManager가 enable=false보다 우선하고 AAR 요청 생성기가 강제 플래그를 자동 추가 |
운영자가 전체 차단으로 오해하지만 관리 요청이 계속 들어올 수 있음 | 별도 전역 실행 차단 또는 호출자별 중지 스위치와 원복 훈련 |
| 이중 이벤트 반영 | 기존 기기 도메인 콜백과 Task 이벤트가 병존 | UI·TTS·IoT 결과가 두 번 반영될 수 있음 | 수신자 멱등성과 이벤트 소유권 표 |
| 버전 조합 | AAR, DeviceAgent와 호출자 APK가 독립 배포될 수 있음 | 지원하지 않는 필드·메서드 전송 | 호환 표와 계약 버전 거절 처리 |
| 진행 중 상태 원복 | 속성을 바꿔도 실행 중인 대기열·Workflow는 남을 수 있음 | 구·신 경로가 동시에 동작할 위험 | 종료 대기·취소·재부팅 정합 절차 |
| 실기기 회귀 공백 | JVM 시험이 MainApi, 모듈과 AAR의 모든 조합을 대신하지 못함 | 출시 환경에서만 시간·권한 문제 발생 | 호출자×메서드×실행 방식×기기 인수 시험 |
30.14 소스 근거와 검증 상태
| 호환 기능 | 구현 근거 | 자동 검증 근거 | 추가 인수 시험 |
|---|---|---|---|
| MainApi 이중 경로 | MainApi.executeMethod() |
TaskManager 통합·실행기 시험 일부 | 원시·비강제·강제 요청을 실제 Binder 호출자로 비교 |
| 기존 대기열 기본값 | TaskManager.isLegacyQueueEnabled() 기본 true |
managerStatus_shouldEnableLegacyQueueByDefault |
속성 해제·설정 상태에서 실제 AMR 명령 비교 |
| 기존 명령 연결 | TaskManager.executeLegacy() |
executeLegacy_whenDefaultEnabled... |
DIRECT·ASYNC·QUEUED_WAIT별 응답 비교 |
| 내부 모듈 분류 | AppCmd.executeThroughTaskManager(), TaskIngressClassifier |
명령·관리 중·조회·콜백 직접 전달 시험 | AMR·UPDATE와 지연 메시지 실기기 회귀 |
| 재진입 방지 | runningManagedTask |
중첩 Task 미생성 시험 | 기기 도메인 콜백 재진입과 다중 스레드 부하 |
| 타입 기반 AAR | TaskSubmitRequest, TaskWorkflowRequest, TaskManagerClient |
Bundle 계약 시험 | AAR·DeviceAgent 버전 교차 설치 |
| 이벤트 분배 | notifyTaskEvent(), shouldBroadcastModuleCallback() |
모니터·이벤트 단위 시험 일부 | 기존 콜백과 AAR 콜백 동시 수신 |
| 스케줄 분리 | Schedule DB와 TaskManager JSON 저장소 | 스케줄 등록·복원·실행 시각 시험 | 재부팅, 시계 변경과 미실행 장시간 검증 |
| 서명 호환 | 플랫폼 서명 특권 앱 배포 계약 | 빌드만으로 확인 불가 | 기존·신규 APK 인증서, UID와 SELinux 비교 |
이 표에서 “자동 검증 존재”는 해당 분기 일부를 시험했다는 뜻이다. 실제 Binder 호출자, 스레드 실행 시점, 플랫폼 권한과 물리 기기 동작까지 동일하다는 의미는 아니다. L3 이상의 적합성은 실기기 증거로 별도 판정한다.
31. 규범 요구사항과 적합성 판정
이 장은 앞의 설명을 구현과 출시 단계에서 판정할 수 있는 요구사항으로 고정한다. 요구사항 ID는 이슈, 소스 검토, 테스트 케이스, 실기기 증거와 릴리스 노트에서 공통으로 사용한다.
31.1 핵심 요구사항 ID
| 요구사항 ID | 강도 | 요구사항 | 쉬운 한 줄 설명 | 최소 증거 |
|---|---|---|---|---|
TM-CORE-001 |
MUST | 모든 관리 대상 실행은 고유 taskId와 생명주기 상태를 가져야 한다. |
무엇이 언제 시작하고 끝났는지 추적할 수 있어야 한다. | TaskRecord 단위 테스트와 런타임 이벤트 |
TM-CORE-002 |
MUST | 최종 상태는 COMPLETED, FAILED, PARTIAL_FAILED, CANCELLED를 구분해야 한다. |
성공, 실패, 일부 실패와 취소를 같은 결과로 합치면 안 된다. | 생명주기 전이 테스트 |
TM-ADM-001 |
MUST | 실행기 호출 전에 메서드, 호출자, 상태와 자원에 대한 실행 허용 판정을 수행해야 한다. | 실행할 수 없는 작업은 기기 동작이 시작되기 전에 차단해야 한다. | 거절 테스트와 미실행 증거 |
TM-ADM-002 |
MUST NOT | TaskManager의 실행 허용 판정은 기존 기기 도메인 안전 정책을 우회하면 안 된다. | 대기열 우선순위가 배터리·오류·개인정보 보호 제한보다 강할 수 없다. | 도메인 정책 회귀 테스트 |
TM-POL-001 |
MUST | 관리 경로는 기존 DeviceAgent 도메인 정책 담당자를 통해 기능을 실행해야 한다. | Task로 감싸도 기존 제품 정책은 그대로 적용돼야 한다. | 기존·관리 경로 허용 결과 비교와 도메인 진입 로그 |
TM-POL-002 |
MUST NOT | 틸트·LCD·팬·도킹 처리처럼 기능에 내재된 정책을 호출자가 재배열 가능한 독립 단계로 분해하면 안 된다. | 내부 안전 동작은 해당 기능이 책임져야 한다. | 이동·일시정지·도착 상태별 부수 정책 증거 |
TM-POL-003 |
MUST | 도메인 정책의 거절, 대기와 자동 전환 결과를 구조화된 Task 결과로 보존해야 한다. | 실행하지 않았는데 성공으로 끝난 것처럼 보이면 안 된다. | errorCode, reason, outcome 계약 시험 |
TM-EXE-001 |
MUST | 관리 대상 실행기는 승인된 기존 기기 도메인 담당자를 호출해야 한다. | TaskManager 안에 이동·청정 기능을 다시 만들지 않는다. | 실행기 연결 검토와 도메인 진입 로그 |
TM-EXE-002 |
MUST | 같은 요청의 중복 물리 효과를 식별하고 방지해야 한다. | 재시도나 재전송으로 같은 동작이 두 번 실행되면 안 된다. | requestId 재전송 테스트 |
TM-CMP-001 |
MUST | 비동기 물리 작업은 최신 완료 증거가 있을 때만 COMPLETED 처리해야 한다. |
함수 호출 성공이 아니라 실제 동작 완료를 확인해야 한다. | 시각 정보가 포함된 콜백·상태 증거 |
TM-CMP-002 |
MUST NOT | 시간 제한을 성공 완료의 대체 조건으로 사용하면 안 된다. | 시간이 지났다는 이유만으로 바이탈사인이나 이동을 성공 처리하지 않는다. | 시간 제한 실패 테스트 |
TM-CAN-001 |
MUST | 취소 가능 Task는 취소 요청과 실제 기기 도메인 중단 결과를 구분해야 한다. | 취소 버튼 접수와 기기가 실제로 멈춘 것은 별도 상태다. | 취소 명령과 정지 증거 |
TM-WF-001 |
MUST | Workflow 단계는 의존 단계가 실제 최종 조건을 만족한 뒤 시작해야 한다. | 앞 단계가 끝나기 전에 다음 동작이 실행되면 안 된다. | 순서가 확인되는 단계 이벤트 추적 |
TM-WF-002 |
MUST | 부분 실패 시 성공한 물리 효과와 실패 단계를 모두 보존해야 한다. | 일부만 실행된 상황을 전체 성공이나 전체 미실행으로 숨기지 않는다. | 부분 실패 결과 테스트 |
TM-SCH-001 |
MUST | 제품 반복 스케줄과 TaskManager 단발 예약의 담당자와 저장소를 분리해야 한다. | 생활 일정과 단발 지연 Task를 같은 예약으로 취급하지 않는다. | DB·저장소 분리 테스트 |
TM-CTX-001 |
MUST | 계획 컨텍스트는 출처, 시각과 최신성을 포함해야 한다. | 오래된 기기 상태를 현재 상태처럼 사용하면 안 된다. | 컨텍스트 스키마·최신성 테스트 |
TM-OBS-001 |
MUST | Task, Workflow, 단계와 콜백은 전체 실행의 상관관계를 복원할 수 있어야 한다. | 화면과 로그에서 어떤 결과가 어떤 요청의 것인지 찾을 수 있어야 한다. | traceId·requestId·taskId 이벤트 사슬 |
TM-COMPAT-001 |
MUST | 선택 적용하지 않은 기존 호출자는 기존 실행 경로를 유지해야 한다. | TaskManager 추가로 기존 앱 명령이 갑자기 다르게 동작하면 안 된다. | 기존 동작 기준 회귀 테스트 |
TM-COMPAT-002 |
MUST | 관리 경로 전환으로 달라지는 반환 시점과 결과 구조를 호출자별로 검증해야 한다. | “접수됨”을 기존의 “완료됨”으로 오해하지 않게 해야 한다. | 기존·관리 경로 응답 비교 |
TM-COMPAT-003 |
MUST | 기존 기기 도메인 콜백은 소비자 전환이 끝날 때까지 유지해야 한다. | Task 이벤트를 추가했다고 기존 화면이나 IoT 콜백을 끊으면 안 된다. | 이중 콜백 테스트 |
TM-COMPAT-004 |
MUST | 관리 Task와 기존 direct 명령은 같은 도메인 실행권과 자원 충돌 판정을 공유해야 한다. | 대기열 밖 명령이 실행 중 Task를 조용히 덮어쓰면 안 된다. | direct↔managed 동시 실행 매트릭스 |
TM-COMPAT-005 |
MUST | 기존 PUI·안전 명령이 관리 동작을 중단하면 관련 Task도 구조화된 최종 상태로 닫혀야 한다. | 기기는 멈췄는데 Task만 계속 실행 중으로 남으면 안 된다. | PUI 취소·저전력 선점 실기기 이벤트 사슬 |
TM-SEC-001 |
MUST | 공개 제어 API는 호출자 권한과 허용 출처를 검증해야 한다. | 아무 앱이나 이동·보안·긴급 명령을 실행할 수 없어야 한다. | Binder·출처 권한 테스트 |
TM-DEP-001 |
MUST | priv-app 배포는 기존 플랫폼 인증서, 소유자·모드와 SELinux 조건을 유지해야 한다. |
디버그 APK나 잘못된 권한으로 시스템 앱을 교체하면 안 된다. | 인증서·해시·권한 증거 |
TM-REL-001 |
MUST | 출시 승인에는 코드, 자동 테스트, 실기기와 원복 증거가 모두 필요하다. | 빌드 성공만으로 제품 동작 완료를 선언하지 않는다. | 출시 증거 묶음 |
31.2 적합성 수준
기능별 상태는 가장 높은 통과 수준 하나로 표현한다.
| 수준 | 이름 | 판정 기준 | 아직 주장하면 안 되는 것 |
|---|---|---|---|
L0 |
정의됨 | 메서드와 요구사항이 문서에 정의됨 | 소스 구현 완료 |
L1 |
연결됨 | 정책, 검증기, 실행기와 콜백 경로가 소스에 연결됨 | 자동 검증 또는 실기기 동작 |
L2 |
코드 검증 | 단위·JVM·빌드·계약 시험 통과 | 물리 기기 성공 |
L3 |
실기기 확인 | 지정 기기·APK·설정에서 실제 성공 증거 확인 | 다른 출시 조합의 보편 동작 |
L4 |
출시 적합 | 호출자 조합, 오류, 취소, 재부팅과 원복 인수 시험 통과 | 장기 운영 안정성 |
L5 |
운영 확인 | 배포 후 지표, 장애와 원복 훈련까지 확인 | 이후 출시 버전의 자동 적합 |
예를 들어 Vision Task가 정상 콜백으로 COMPLETED된 것은 최대 L3의 “관찰 호출 성공” 근거다. 원하는 객체를 찾았거나 추적 기능이 있다는 뜻은 아니다. 의미 있는 객체가 실제로 검출됐는지는 별도 인수 시험으로 확인한다.
31.3 기능 적합성 카드
각 taskMethod는 코드와 문서에 흩어진 내용을 다음 한 장의 카드로 모아야 한다.
| 항목 | 작성 내용 |
|---|---|
| 기능 | 표준 taskMethod, 사용자·시스템 목적 |
| 실제 담당자 | 기존 기기 도메인 관리자·제어기·API |
| 입력 계약 | 필수 필드, 타입, 허용 별칭과 기본값 금지 항목 |
| 호출자 계약 | 허용 출처, 권한과 우선순위 상한 |
| 실행 계약 | 실행 방식, 대기열, 시간 제한, 재시도와 중복 방지 키 |
| 상태·자원 | 허용 주 상태, 차단 상태와 필수 자원 |
| 완료 계약 | 시작·완료·중단 증거, 식별 키, 최신성과 안정 조건 |
| 취소·복구 | 취소 가능 여부, 취소 메서드와 보상 동작 |
| 결과 계약 | 성공 결과, 실패 사유 연결과 복구 가능성 |
| 관찰 계약 | 진행률, 이벤트와 계획 컨텍스트 반영 필드 |
| 호환 계약 | 기존 메서드·필드·콜백, 반환 차이와 원복 |
| 검증 상태 | L0~L5 수준, 테스트·증거 위치와 미해결 이슈 |
기능 카드 예시: setMoveTo
| 항목 | 현재 기준 |
|---|---|
| 목적 | 등록된 목표 공간 또는 좌표로 이동 |
| 실제 담당자 | Movement 실행기를 거친 기존 AMR·MovingController 계열 |
| 입력 | 표준 위치·공간 ID와 표시 이름. 임의 공간 추정 금지 |
| 실행 | ASYNC, movement 대기열, HIGH 우선순위와 시간 제한 정책 적용 |
| 시작 조건 | AMR 연결, 지도·대상 확인과 배터리·개인정보 보호·오류·LLM 정책 허용 |
| 완료 | 목표와 일치하는 최신 movement.arrived 및 이동 안정 상태 |
| 취소 | stopMovement 요청 후 실제 이동 중지 증거 |
| 선행 정리 | 청정 중이면 중지 후 cleaning.stopped를 확인하는 관리 전환 가능 |
| 실패 | 대상 없음, 정책 거절, AMR 사용 불가와 시간 초과 등을 실패 사유로 분리 |
| 호환 | 기존 원시 이동 경로를 유지하며 호출자별 forceTaskManager 선택 적용 |
31.4 요구사항 추적 사슬
구조도는 제품 요구사항에서 TM 요구사항 ID, 기능 카드, 정책·검증기·실행기·완료 증거 소스, 자동화 시험, 실기기 증거, 출시 판정과 원복 절차까지 이어지는 추적 사슬을 나타낸다.
각 변경 PR 또는 출시 노트에는 최소한 다음을 남긴다.
requirements: [TM-CMP-001, TM-COMPAT-002]
capabilities: [setMoveTo]
callers: [APP, CLOUD]
source_changes: [...]
automated_tests: [...]
device_evidence: [...]
compatibility_result: pass | conditional | fail
원복: forceTaskManager 제거 또는 출시 산출물 복원
open_risks: [...]
31.5 출시 판정표
| 판정 | 조건 | 출시 처리 |
|---|---|---|
PASS |
필수 요구사항과 대상 호출자·기기 조합이 모두 통과 | 계획 범위 출시 가능 |
CONDITIONAL |
핵심 안전·호환 요구는 통과했지만 일부 조합이 미검증 | 범위 제한, 기능 플래그와 원복 방법 명시 |
FAIL |
중복 실행, 잘못된 완료, 기존 기능 회귀, 권한 또는 원복 실패 | 출시 차단 |
NOT_APPLICABLE |
해당 기능에 적용되지 않는 요구사항 | 적용 제외 근거 기록 |
다음 항목은 예외 승인으로 넘길 수 없는 출시 차단 조건이다.
- 기존 호출자의 기능 회귀 또는 중복 물리 실행
- 실제 완료 증거 없는 성공 처리
- 취소 후 기기 동작이 계속되는 상태
- 권한 없는 호출자의 제어 API 실행
- 디버그 인증서 또는 플랫폼 서명 불일치
- 원복 경로 부재
31.6 변경 관리
- 공개 필드, 생명주기, 실패 사유 또는 콜백 변경은 계약 변경으로 분류한다.
- 선택 필드 추가는 minor version, 기존 의미 변경이나 삭제는 major version 대상으로 본다.
- 내부 클래스 이름 변경은 외부 계약 변경이 아니지만 소스 추적 정보를 갱신한다.
- 별칭 추가는 호환 범위 확대다. 별칭을 제거하려면 호출자 현황과 폐기 유예 기간이 필요하다.
- 정책 기본값 변경은 API 구조가 같아도 동작 호환성 변경이다. 실기기 회귀 시험과 릴리스 노트가 필요하다.
- 목표 사양을 현재 구현으로 승격할 때 해당 요구사항의 테스트와 증거를 함께 연결한다.
제7부 · 용어와 최종 원칙 — 32~34장은 용어, 최종 설계 원칙과 세부 참조 문서를 정리한다.
32. 용어집
| 용어 | 정의 |
|---|---|
| Task | 하나의 관리 가능한 실행 단위 |
| Workflow | 순차·병렬 단계를 가진 상위 Task |
| 단계(Step) | Workflow 내부의 실행 항목 |
| 실행 허용(Admission) | 실행 전에 입력, 출처, 상태와 자원을 검사하는 과정 |
| 실행 정책(Policy) | 메서드별 실행 방식, 대기열, 우선순위, 시간 제한, 재시도와 취소 규칙 |
| 실행기(Executor) | Task 계약을 기존 기기 도메인 호출에 연결하는 어댑터 |
| 완료 증거(Evidence) | 실제 완료·취소·실패를 증명하는 콜백 또는 상태 |
| 완료 조건(Completion target) | 어떤 완료 증거를 기다릴지 나타내는 문자열 |
| 최종 상태(Terminal) | 더 이상 실행되지 않는 완료·실패·취소 상태 |
| 보상 동작(Compensation) | 이미 발생한 물리 효과를 안전한 상태로 되돌리는 작업 |
| 선점(Preempt) | 새 요청이 기존 Task를 정리하거나 대체하는 정책 |
| 단발 예약 Task(Deferred task) | 미래의 특정 시각에 한 번 실행 허용 절차에 진입하는 TaskManager 예약 |
| 제품 스케줄(Product schedule) | 반복 생활 일정과 제품 고유 스케줄 |
| 계획 컨텍스트(Planning context) | 계획에 사용할 현재 기기 상태 스냅숏 |
| 재계획(Replan) | 기존 목표를 유지하면서 단계와 기능을 다시 구성하는 상위 판단 |
| AAR | 제품 시스템 앱이 TaskManager를 타입 기반 API로 호출하기 위한 Android 라이브러리 |
33. 최종 설계 원칙
- 기능을 다시 만들지 말고 실행 생명주기를 공통화한다.
- 명령 접수와 실제 완료를 분리한다.
- 행동 요청과 센서·콜백을 분리한다.
- 상위 호출자는 목적과 실행 구성을, TaskManager는 실행 관리를, 기기 도메인은 물리 동작과 상태를 소유한다.
- 모든 기능은 정책, 스키마, 실행기와 완료 증거가 갖춰져야 실제 사용 가능한 기능이 된다.
- 취소는 성공이 아니며, 부분 실패도 성공으로 숨기지 않는다.
- 정상 진행은 기기 런타임이 처리하고 의미적 변경이 필요할 때만 재계획한다.
- 기존 기능과 호출자를 유지하면서 호환 경로를 통해 단계적으로 전환한다.
- AAR과 스키마 버전으로 외부 계약을 내부 코드와 분리한다.
- 구현, 코드 검증, 실기기 검증과 제품 인수를 항상 구분한다.
34. 관련 문서
문서 전체 진입점은 SoC TaskManager Framework다.