← Docs hub

TaskManager 사양 5 · 외부 연동과 기존 시스템 호환

None
사양 허브DeviceAgent MR6Spec 1.9

AAR, IoT/MQTT, 선택적 Planner와 기존 direct 실행 경로의 점진 전환 방식을 정의한다.

이 장의 결론: 기존 채널과 응답 계약은 유지하고, 관리가 필요한 요청만 명시적으로 Task 또는 Workflow 경로에 올린다.

18. TaskManagerClient AAR

TaskManager Core는 호출 채널에 종속되지 않는다. 시스템 앱은 typed AAR, IoT는 MQTT, Cloud·On-device bridge는 Bundle/JSON 변환을 사용하지만, 최종 요청은 같은 submitTask 또는 submitWorkflow 계약으로 수렴해야 한다.

AAR은 시스템 앱이 문자열과 Bundle을 직접 조립하지 않도록 제공하는 product-level facade다. 다음 원칙을 지킨다.

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 계약으로 전달한다.

전체 payload와 운영 속성은 MQTT Task Contract을 기준으로 한다.

20. 선택 연동: Cloud Planner와 A2A

20.0 선택적 상위 연동의 경계

기본 경로에는 Planner가 필요하지 않다. 앱·PUI·IoT·예약과 사전 정의 Workflow는 상위 의미 추론 없이 같은 Core를 사용한다. Planner가 연결되더라도 실행 허용, 자원 정책, 물리 완료 증거와 최종 상태 판정은 DeviceAgent TaskManager와 각 기기 도메인이 소유한다. 상위 Planner가 없어도 기기 내부에서 안전한 생명주기를 유지한다.

Planner와 TaskManager의 제한된 폐루프

상위 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, 시험, 변경과 참조 규격을 정리한다.

30. 기존 시스템 호환성과 점진적 전환 사양

TaskManager 도입은 기존 DeviceAgent 기능을 다른 구현으로 교체하는 작업이 아니다. 기존 PUI, IoT, 시스템 앱, Schedule과 Voice/LLM 호출이 사용하던 MainApi와 기기 도메인 구현을 유지하고, 관리가 필요한 요청만 TaskManager 생명주기에 편입하는 점진적 확장이다.

기존 실행 경로와 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을 함께 운영 모든 시스템 앱의 동시 전환
원복 호출자 또는 시스템 속성 단위로 기존 경로 복귀 데이터와 앱을 되돌릴 수 없는 일괄 전환

호환성은 “컴파일된다”가 아니라 다음 네 수준으로 판정한다.

  1. 호출 호환성: 기존 메서드와 필드를 계속 보낼 수 있다.
  2. 동작 호환성: 같은 기기 도메인이 같은 물리 동작과 안전 정책을 수행한다.
  3. 관찰 호환성: 기존 콜백과 UI·IoT 상태 갱신이 유지된다.
  4. 운영 호환성: 배포, 재부팅 복원, 모니터링과 원복이 가능하다.

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 기존 경로

30.2.2 외부 MainApi 관리 경로

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 선택 적용 구조

TaskManager 도입으로 바뀌는 범위는 MQTT broker, topic, 인증, QoS와 재연결 같은 전송 계층 전체가 아니다. 바뀌는 부분은 명령 payload가 직접 실행인지 관리 대상 Task·Workflow인지 표현하는 응용 계약과, 관리 요청의 진행·완료를 돌려주는 결과 계약이다.

호출 경로 기존 호출 유지 관리가 필요한 단일 동작 여러 단계 Workflow 현재 구현 경계
원격 App·IoT → MQTT 기존 topic과 기능 payload를 그대로 전송 기존 request.methodrequest.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로 같은 실행을 묶고 수신자는 중복 반영하지 않아야 한다.

채널 전환 순서
  1. 기존 MQTT·App 명령과 응답을 기준선으로 고정한다.
  2. 취소·진행률·물리 완료 추적이 필요한 메서드 하나를 선택한다.
  3. IoT는 request.task, System App은 AAR, LLM은 구조화된 device request로 같은 Task 의미를 만든다.
  4. 기존 callback과 Task event가 같은 물리 실행을 가리키는지 확인한다.
  5. 단일 Task가 안정화된 뒤 공통 submitWorkflow ingress를 추가한다.
  6. 호출자×메서드 단위로 확대하며 기존 direct 경로는 원복 수단으로 유지한다.

이 구조에서 호출 채널은 서로 달라도 TaskManager가 받는 최종 계약은 동일하다. 반대로 센서 update, heartbeat, 조회 결과와 단순 상태 동기화는 실행 생명주기가 아니므로 기존 메시지 경로에 남긴다.

30.2.6 기존 direct 명령과 관리 Task의 동시성

현재는 관리 Task끼리의 순서는 TaskManager가 통제하지만, 비관리 direct 명령은 대기열 밖에서 실행된다. 두 경로는 기존 DeviceAgent 도메인 정책에서 다시 만나므로 물리 안전 제한은 공유하지만, 실행 순서와 Task 상태까지 자동으로 정합되는 것은 아니다.

기존 direct 명령과 관리 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

단순히 CmdPolicyManagerPOLICY_NOT_ALLOWED를 반환하는 것으로 끝내면 호출자는 “왜 안 됐는지”, TaskManager는 “기존 작업이 계속 유효한지”를 알 수 없다. 도메인 정책 결과를 errorCode, reason, 점유 자원과 관련 taskId로 연결해야 동시성 호환이 완성된다.

단계적 적용
  1. 기존·관리 경로의 동시 실행 조합을 로그로만 관찰한다.
  2. 이동·청정·보안·화면/카메라 세션의 자원 소유권과 사용자 취소 결과를 표준화한다.
  3. 충돌 가능 direct 명령에 공통 실행권 검사를 적용하되 기존 응답 형식은 유지한다.
  4. 검증된 장기 메서드만 내부 단일 Task 승격 대상으로 확대한다.
  5. PUI·오류·저전력 선점이 기존 관리 Task를 올바른 terminal 상태로 닫는지 실기기에서 검증한다.
  6. 호출자×메서드 단위 회귀가 끝날 때까지 기존 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 도입 전후에 바뀌면 안 되는 호환 불변 조건이다.

  1. 같은 요청은 Movement, Cleaning, Schedule, Security 등 기존 수행 주체가 처리한다.
  2. 기존 PUI, IoT와 시스템 앱의 원시 메서드는 선택 적용 전까지 기존 경로를 사용한다.
  3. 기존 기기 도메인 콜백과 상태 갱신은 계속 발행된다.
  4. LLM, 배터리, AMR, 개인정보 보호, 오류와 주 상태 제한은 기존 기기 도메인이 최종 판정한다.
  5. 같은 기기 동작이 기존 경로와 관리 경로에서 중복 실행되지 않는다.
  6. TaskManager가 비활성화돼도 기존 핵심 기능은 원시 경로로 수행할 수 있어야 한다.
  7. 기존 제품 스케줄의 등록, 조회, 실행 의미와 DB 소유권은 유지한다.
  8. 시스템 앱 패키지, 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를 추가로 사용할 수 있다.

따라서 호출자별 전환 전에 다음을 명시한다.

30.6 메서드·필드 별칭 계약

요약: 메서드·필드 별칭은 등록된 항목에만 적용되며 모든 과거 입력을 자동으로 호환하지 않는다.

별칭 처리는 기존 요청 데이터를 모두 자동 수용하는 범용 기능이 아니다. TaskMethodAliasResolver, TaskFields와 실행기 어댑터에 등록된 범위만 계약이다.

소스 표현 쉬운 한 줄 설명 호환성에서 확인할 점
TaskMethodAliasResolver 과거 기능 이름을 현재 표준 기능 이름으로 바꿔 주는 이름 변환기 등록되지 않은 이름은 자동으로 추정하지 않는다.
TaskFields 여러 모듈이 함께 사용하는 Task 필드 이름을 모아 둔 공통 정의 호출자와 실행기가 같은 필드를 쓰는지 확인한다.
실행기 어댑터 표준 Task 입력을 기존 기능이 이해하는 입력으로 바꾸는 연결 코드 변환 과정에서 값이 빠지거나 임의 기본값이 생기면 안 된다.
queue / queueKey 작업을 어느 실행 대기열에서 처리할지 지정하는 필드 클라이언트가 쓰는 이름과 Core가 읽는 이름을 하나로 맞춰야 한다.
엄격한 입력 검증 정의되지 않은 필드를 오류로 차단하는 검사 방식 기존 호출자의 필드를 조사하지 않고 켜면 정상 요청도 거절될 수 있다.
호출 필드 계약 확인 실제 호출자가 보내는 필드 이름과 값의 전체 목록을 확인하는 작업 문서에 없는 기존 입력까지 전환 전에 확인한다.
기준 요청 회귀 시험 현재 정상 동작하는 대표 요청을 고정해 변경 전후 결과를 비교하는 검사 별칭이나 검증기 변경으로 생기는 회귀를 자동으로 찾는다.

현재 대표 호환 범위:

현재 알려진 정합 공백:

따라서 엄격한 입력 검증을 기본 활성화하기 전에 메서드별 호출 필드 계약 확인과 기준 요청 회귀 시험을 수행해야 한다. 현재 기본값을 false로 유지하는 것은 기존의 유연한 요청이 갑자기 거절되는 상황을 막기 위한 호환 장치다.

30.7 콜백과 이벤트 호환

요약: 기존 콜백은 유지하고 TaskManager 이벤트로 진행률과 완료 상태를 추가한다.

관리 대상 Task는 기존 콜백을 대체하지 않고 완료 증거로 사용한다.

기존 PUI·IoT·시스템 콜백은 유지한다. 관리 대상 Task와 연결된 콜백만 CompletionBridgeTaskCompletionStateStore와 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, 모니터 이벤트 중 어느 경로를 사용할지 계약해야 한다.

호환 규칙:

  1. 기존 콜백 수신자를 유지한 상태에서 Task 이벤트를 추가 발행한다.
  2. 콜백의 기능 의미를 TaskManager에서 다시 추정하지 않는다.
  3. Task 이벤트에는 taskId, Workflow·단계 상관관계와 최신 시각을 추가한다.
  4. 같은 콜백이 재전송돼도 최종 이벤트는 멱등하게 처리한다.
  5. Task Monitor가 콜백을 받지 못해도 기존 기능 상태를 덮어쓰지 않는다.
  6. 기존 콜백 제거는 모든 수신자의 전환과 원복 검증 이후 별도 출시에서 수행한다.

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를 넣으면 권한 오류나 부팅 문제가 생길 수 있다.

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이면 활성화 속성보다 강제 실행을 우선한다. TaskSubmitRequestTaskWorkflowRequest도 강제 실행 플래그를 자동으로 추가한다. 따라서 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 이상의 적합성은 실기기 증거로 별도 판정한다.


Keyboard shortcuts

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

Structured queries

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

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

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