← Docs hub

Task 완료 관측 이관: 원본 분석과 작업별 연결 설계

상태: TTS 내부 연결 구현·JVM 검증 완료. 전체 도메인 이관·장치 연결 완료는 아니다.

이번 변경을 폴더로 이해하기

TTS 완료 처리의 도메인·작업·근거 책임과 미연결 장치 경계

SVG 확대 · Mermaid 원본 · 전체 프레임워크·폴더 지도

그림은 전체 프레임워크 중 TTS 완료 처리 경로만 확대한다. 전체 지도와 다른 대체 구조가 아니다. 앞부분 skix-framework/base/services/core/java/com/sk/airbot/frameworkservice/server/를 생략하면:

폴더 답해야 하는 질문 맡기지 않는 책임
domain/llm/completion/ 이 재생 세션이 실제로 시작했고 끝났는가? 다른 도메인 작업의 완료 판정
execution/task/completion/ 이 결과가 등록한 작업·시도·Runtime 세대에 해당하는가? IDLE 같은 장치 상태를 직접 해석
execution/task/ 작업을 어떤 상태로 전이할 수 있는가? 스피커 출력·장치 중단 성공을 추측
execution/evidence/ 어떤 사건과 실행 키를 근거로 남기는가? 근거가 있다는 이유만으로 Task 성공 처리
control/lifecycle/ 담당 서비스가 준비되어 있고 같은 세대인가? 재생 중·재생 완료 같은 업무 상태 소유

예를 들어 이전 작업의 IDLE이 늦게 도착해도 새 작업의 성공으로 바꾸지 않아야 한다. 취소 요청 중 성공 관측이 와도 그것을 “중단 확인”으로 바꾸지 않는다. 시간초과 때 내부 감시를 정리하는 것 역시 실제 스피커가 멈췄다는 뜻은 아니다.

원본의 작업 식별자 없는 콜백은 새 키를 임의로 붙여 연결하지 않는다. 그림의 황색 실행 어댑터는 후속 연결 범위다. Resource·Capability와 Task 기본 등록은 별도 Runtime 구현으로 진행하며 LLM/TTS 장치 결선과는 구분한다.

1. 확인한 현재 상태

TTS 첫 이관: 내부 연결과 회귀 검증 완료

MR7 refactor/blueprint-foundation에 아래 경로를 구현했다. 모두 그림 B~D의 내부 경로이며, 기존 DeviceAgent 상태 콜백을 바로 연결한 것은 아니다.

구성요소 이번에 구현한 내용
domain/llm/completion/TtsTaskCompletionService 재생 시작 전 IDLE 무시, 시작 후 IDLE 완료, STOP·웨이크워드 중단, 단일 세션과 명시적 정리
domain/llm/LlmManagerService 선택적 완료 서비스 소유와 onStop() 정리
execution/task/completion/TaskExecutionKey 작업·시도·Runtime 세대를 구분하는 불변 키
execution/task/completion/TaskCompletionCoordinator 실행 전 등록, 키·도메인·표적·순서 검증, Task 상태 전이 요청과 근거 기록

서버 JVM 33개 클래스 / 193개 검사, SDK JVM 11개 클래스 / 37개 검사가 실패·오류·건너뜀 없이 통과했다. 신규 TTS/Coordinator 25개와 실행 키 1개는 서버 193개에 포함된다. release Java 컴파일과 폴더·레이어 검사 및 두 검사 도구의 회귀 검사도 통과했다. 전체 Gradle 명령은 BUILD SUCCESSFUL in 11s이며 SDK 테스트는 최신 결과를 재사용했다. Build Tools 34.0.0 지정 대신 AGP가 35.0.0을 사용하는 기존 경고는 남아 있다.

최종 리뷰에서는 다음 경계를 보완했다.

남은 연결: 실행 키 없는 onChange(status, ttsType)는 현재 작업에 임의 배정하지 않는다. Resource·Capability와 Task의 기본 Runtime 구성은 별도 구현 단계로 갱신했다. 실행 요청부터 결과까지 키를 유지하는 어댑터는 여전히 후속 작업이다. timeout()은 감시만 해제하며 Task의 TIMED_OUT 전이나 스피커 정지를 합성하지 않는다. 서비스 세대가 바뀌었는데 onStop()을 거치지 않는 복구 경로는 명시적 cleanup이 필요하다. 근거 전달의 도메인 간 전역 순서는 보증하지 않는다. APK·AOSP 제품 이미지·실기기 완료 검증은 하지 않았다.

소스 보고서: docs/refactor/skix-tts-completion-port-2026-09-08.md.

후속 실행 검증: 원본 JVM 250개 통과

2026-09-08에 아래 MR6 커밋의 apps/DeviceAgent를 git archive로 임시 디렉터리에 추출했다. 사용 중인 MR6 브랜치를 전환하지 않았고, 원본 생산·테스트 소스를 변경하지 않았다. Watcher·TTS 8개를 먼저 실행한 후 Task 패키지와 보안 완료 보고까지 확대해 28개 테스트 클래스 / 250개 검사, 실패·오류·건너뜀 각각 0을 확인했다. 8개는 250개에 포함되므로 합산하지 않는다.

이관할 책임 원본 테스트 수 MR7 소유 폴더
완료 감시·결과 우선순위 TaskCompletionWatcherTest 5 execution/task/와 도메인 완료 해석 분리
시작 후 TTS 완료·취소 LlmTaskCompletionBridgeTest 3 domain/llm/
주행 전 청정 정지·이미 스테이션인 경우 MovementTaskExecutorTest 7 domain/amr/와 선행 조건 조정
이미 운전·정지한 청정 상태 처리 CleaningAmpTaskExecutorTest 8 domain/cleaning/
앱 세션·보안 완료 보고 AppSessionCompletionBridgeTest / WssTaskCompletionReporterTest 8 domain/ui/, domain/security/
도메인 자원 충돌 조건 TaskDomainResourcePolicyTest 9 control/resource/, control/policy/와 도메인 요구 조건
작업 관리·복합 흐름 TaskManagerTest / TaskManagerIntegrationTest 94 execution/task/, execution/workflow/
관측·계획 입력·모니터링 등 나머지 19개 클래스 116 후속 책임 분류

원본 프로젝트에서 실행한 명령:

ANDROID_HOME=/home/silogood/Android/Sdk ANDROID_SDK_ROOT=/home/silogood/Android/Sdk \
  ./gradlew --no-daemon :app:testDebugUnitTest \
  --tests 'com.sk.airbot.deviceagent.task.*' \
  --tests com.sk.airbot.deviceagent.wss.WssTaskCompletionReporterTest

원본 wrapper 8.9 / AGP 7.3.0 / OpenJDK 17.0.20을 사용했다. 확대 실행은 BUILD SUCCESSFUL in 27s이며 Gradle 작업 1개 실행·20개 최신 상태였다. 테스트 수는 JUnit XML의 suite 속성을 합산했다. Manifest·Gradle deprecation 경고는 남아 있다.

검증 한계: 원본의 테스트용 Bundle·TextUtils와 가짜 장치 실행기를 사용한 JVM 결과다. 실제 모터·팬·TTS 출력, Android Binder, MR7 이관 동등성은 검증하지 않았다. 이 원본 테스트 실행 시점에는 신규 Coordinator가 설계 검토안이었다. 이후 TTS 내부 연결을 구현·검증했으며, Resource·Capability 구현과 Task의 기본 Runtime 연결 결과는 후속 구현 문서를 참조한다. 재현 경로·28개 클래스별 결과는 MR7 저장소의 docs/strategy/short-term/2026-09-08-mr6-task-migration-baseline.md에 기록했다.

설계 분석 시점의 소스 상태

MR7 기준 커밋은 2d462ad, 브랜치는 refactor/blueprint-foundation이다. execution/evidence/EvidenceManagerService는 관측 보관을 맡지만 Task 완료를 판정하지 않는다. execution/task/TaskManagerService.transition()은 상태 전이와 사유만 검사하며 관측 식별자를 요구하지 않는다. 이 분석 시점의 domain/amr/AmrManagerService, domain/llm/LlmManagerService는 생명주기 소유권 클래스였다. 이름이 존재하는 것을 실제 완료 판정·장치 연결 구현으로 해석하면 안 된다.

MR6 원본은 a1-packages-mr6의 task_manager 커밋 d1d8dfbc4c807a32990f4350cf09c49f159f5848이다. 현재 MR6 체크아웃은 다른 브랜치이므로 git show task_manager:<path>로 읽었다. 이 문서의 MR6 경로 앞부분은 apps/DeviceAgent/app/src/main/java/com/sk/airbot/deviceagent/다.

2. 완료 표적 24개의 도메인 소유권

아래 값은 task/TaskCompletionStateStore.java:15-38의 원본 문자열이다. 원본 wire 값을 유지하되 공통 저장소에 모든 도메인의 상수를 몰아넣지 않는다. 소유권 열은 이관 설계이며 신규 파일이 이미 있다는 뜻이 아니다.

원본 표적 현재 생산자 / 연결 근거 이관 소유권
movement.arrived, movement.stationCharging, movement.rotationCompleted moving/RobotMovementController.java:643, moving/MovingLocationManager.java:596, moving/MovingController.java:56 domain/amr/
cleaning.started, cleaning.stopped, cleaning.stepComplete, cleaning.reportDone cleaning/BaseCleaningManager.java:216, cleaning/BasicCleaningManager.java:227, cleaning/MovingCleaningManager.java:737 domain/cleaning/
interaction.started, interaction.arrived, interaction.actionStarted, interaction.actionEnded, interaction.returning, interaction.completed interaction/InterScheduleManager.java:502 복합 순서는 execution/workflow/, 개별 실행 판정은 담당 domain. 세부 이관은 이번 첫 TTS 연결 범위 밖
security.started, security.paused, security.resumed, security.stopped, security.patrolCompleted wss/WssTaskCompletionReporter.java, wss/WssManager.java:1149 domain/security/
mapping.dataReceived main/MainService.java:121 domain/amr/
app.sessionStarted, app.sessionEnded task/AppSessionCompletionBridge.java:31 domain/ui/의 앱 세션 관측 경계
tts.playbackStarted, tts.playbackEnded task/LlmTaskCompletionBridge.java:60 domain/llm/
ui.screenApplied main/api/MainApi.java:387 domain/ui/

areaId는 실제로 방 번호만 담지 않는다. TTS에는 completionKey, 앱에는 packageName, 상호작용에는 별도 key가 들어간다. 새 공통 계약에서 이를 무조건 공간 ID로 정의하지 않는다.

3. 도메인별 보존해야 할 완료 조건

주행

task/MovementTaskExecutor.java는 주행 명령 전에 청정이 동작 중이면 청정 정지를 요청하고 정지 관측을 기다린다. 주행·청정 간 전이 정책이 이미 Task 실행기에 들어 있는 사례다. 이 정책은 AMR이 Cleaning 내부 상태를 직접 읽는 방식으로 복제하지 않고 제어 계층과 도메인 협력으로 분리해야 한다.

waitForMovementArrived()는 명시적 도착 관측뿐 아니라 현재 위치·주행 여부를 확인한다. 대상 위치이며 주행 중이 아니고, 이미 대상에 있었거나 이동을 실제 관측한 경우 2초간 위치가 유지되면 도착으로 인정한다. 그 뒤 waitForMovementIdle()은 최대 30초간 컨트롤러 IDLE이면서 returning·docking이 아닌 상태를 별도로 기다린다. 충전 복귀는 이미 스테이션에 있으면 즉시 결과를 내는 별도 분기다.

따라서 범용 Evidence 이벤트 하나로 이 조건들을 대체하면 원본 사양이 사라진다.

청정

task/CleaningAmpTaskExecutor.java는 명령 전 상태를 보관한 뒤 이미 해당 구역에서 시작한 상태, 이미 정지한 상태를 각각 인정한다. 기본 운전은 cleaning.stopped, 다른 운전은 cleaning.reportDone을 기본 표적으로 선택하며 요청 가능한 표적도 제한한다. 시작 후 정지가 표적인 경우 dwell 시간을 제한한 뒤 정지 명령을 보낸다. 청정 시작·단계 완료·전체 보고 완료는 서로 다른 사건이다.

TTS

task/LlmTtsTaskExecutor.java는 tts.playbackEnded 완료를 요청한 경우에만 키를 요구하고 감시한다. 키 후보는 completionKey → 외부 step ID → requestId → traceId 순서다. task/LlmTaskCompletionBridge.java는 활성 재생 한 건을 보관하고, 처리·재생 상태를 본 뒤에만 IDLE을 완료로 인정한다. 시작 전 IDLE은 무시한다. 웨이크워드 취소와 STOP은 중단이다. 단순 메서드 반환이나 시작 전 IDLE을 완료로 바꾸면 안 된다.

앱과 시스템 계열

task/AppSessionCompletionBridge.java는 running을 먼저 본 패키지만 종료 대상으로 인정한다. 취소 별칭과 실패 별칭을 구분하지만, 그 외 running 이후 상태는 종료 성공으로 처리한다. 이 fallback을 새 엄격한 계약으로 확대 해석하지 않고 호환 어댑터 동작으로 명시한다. task/MainApiTaskExecutor.java에는 보안 결과 코드 검사, 지도 수신 감시, 예약 저장 후 검사가 함께 있다. 이를 하나의 공통 ManagerService로 복제하지 않고 각각 해당 도메인·예약 경계로 분리한다.

4. 공통 저장소·감시기의 실제 제약

소스에서 확인한 동작 이관 시 의미
TaskCompletionStateStore.put()은 target|area와 target|빈값을 모두 갱신 빈 키 조회는 모든 구역의 최신 사건을 볼 수 있음. 작업별 식별이 아님
성공·중단을 별도 맵으로 보관 양쪽이 동시에 남을 수 있음
TaskCompletionWatcher.waitFor()는 성공 검사 후 중단 검사 둘 다 있으면 성공 우선. TaskCompletionWatcherTest.waitFor_whenCompletionAndAbortObserved_shouldPreferCompletion이 명시적으로 보장
표적·구역 문자열을 |로 결합 임의 문자열의 구분자 충돌 가능. 새 내부 키는 구조화된 값으로 분리
observedAt >= since와 사건 이후 경과시간으로 안정성 판정 지속 상태를 관측한 것이 아님. 동일 표적 재발행은 시각을 덮어씀
벽시계 deadline, 500ms sleep, 최소 timeout 1초, 기본 30초, 기본 stable 500ms 새 서비스 스레드를 블로킹하지 않는 스케줄링 경계와 시간 주입이 필요
TTS timeout 경로는 bridge 활성 항목을 해제하지 않음 상태 콜백이 오지 않으면 다음 begin이 resource_busy가 될 수 있는 정적 위험. 실기기 재현 결과는 아님
TaskModuleExecutor.writeWiredResult()는 실행 메서드 반환 후 wired=true 기록 wired는 장치 완료 증거가 아님

성공 우선 규칙을 전역 중단 우선으로 변경하지 않는다. 주행의 정상 도착 후 IDLE도 중단 관측을 기록할 수 있으므로 도메인이 정상 후속 상태인지 실제 중단인지 먼저 해석해야 한다.

5. 비교와 권장안

  1. 원본 Store/Watcher를 그대로 복사: 호환성은 높지만 전역 키·Bundle·폴링·도메인 조건 혼재가 남는다. 목표 구조와 맞지 않는다.
  2. 권장: 도메인별 완료 조건 + 작업 시도별 공통 연결: 원본 사양은 도메인으로 옮기고 Task에는 작업·시도·취소·시간초과 관리만 둔다. 기존 wire 해석은 compatibility에 둔다.
  3. 모든 Evidence 이벤트로 Task를 자동 성공 처리: 구현은 짧지만 시작/단계/전체 완료와 재시도 관측을 혼동한다. 채택하지 않는다.

6. 신규 계약 제안과 폴더 배치

아래는 승인된 전체 이관 계약이다. TTS 내부 경로부터 구현하며, AMR·Cleaning·UI·보안·호환 변환의 모든 행이 이미 구현되었다는 뜻은 아니다. Java 서버 공통 패키지 루트는 skix-framework/base/services/core/java/com/sk/airbot/frameworkservice/server/다.

신규 파일 / 위치 단일 책임
execution/task/completion/TaskExecutionKey.java taskId·attemptId·runtimeGeneration을 별도 필드로 보관. 문자열 결합이나 areaId를 작업 ID로 쓰지 않음
execution/task/completion/TaskCompletionObservation.java 실행 키, eventId, 도메인, 표적, 관측 순번, 정규화된 도메인 결과 보관
execution/task/completion/TaskCompletionCoordinator.java 현재 실행 키와 사건을 연결하고 중복·이전 시도·종료 후 사건을 거부. TaskManagerService만 상태 writer로 사용
domain/amr/completion/ 도착·위치 안정화·IDLE·스테이션 조건과 AMR 완료 상수
domain/cleaning/completion/ 청정 시작·정지·단계·보고 조건과 상수
domain/llm/completion/ 시작 관측 이후 TTS 완료·취소 조건과 활성 세션 정리
domain/ui/completion/, domain/security/completion/ 앱/화면 및 보안 상태를 각 도메인의 결과로 변환
base/compatibility/java/ 기존 completionTarget·completionKey·시간 Bundle 필드 해석. 원본 문자열 상수·매핑 유지
base/services/tests/src/.../ 각 생산 패키지를 따라 원본 동작과 신규 상관관계 테스트 배치

공개 SDK에 도메인 이벤트를 노출할 때만 base/core/java/의 해당 도메인 계약으로 승격한다. 내부 완료 표적 전부를 공개 API로 고정하지 않는다.

사건 접수 규칙

7. 구현 순서와 통과 조건

  1. 원본 감시기 테스트 5개와 TTS bridge 테스트 3개를 특성 테스트로 보존한다. 원본 success 우선, 시작 전 IDLE 무시, 사용자 취소를 포함한다.
  2. 첫 세로 연결은 TTS로 한정한다. 단일 활성 재생이라는 원본 제약을 보존하면서 완료 키·시도·시작 관측·취소·timeout 정리를 domain/llm에서 구현한다. 이는 다른 도메인의 제외가 아니라 첫 검증 경로다.
  3. Coordinator 테스트: 일치/불일치 task·attempt·generation, 등록 전 사건, 중복, 종료 후 사건, CANCELLING+success, 실제 취소 확인, 준비 상태 장애, 근거 보관 실패.
  4. AMR·Cleaning을 각각 이식한다. 도착 후 IDLE, 2초 위치 안정화, 청정 정지 선행, 이미 실행/정지 상태, 시작·단계·보고 분리를 검증한다.
  5. UI·보안·상호작용을 실제 생산자에 연결한다. 상호작용은 Workflow와 개별 도메인의 책임을 추가 분석한 뒤 나눈다.
  6. 기본 구성에 Task를 넣기 전에 실제 Resource·Capability 서비스 의존성을 구현한다. 테스트용 빈 구현으로 제품 기본 구성을 채우지 않는다.
  7. 전체 JVM·release 컴파일·레이어 검사 후 Android 전달·기기 검증으로 확장한다. 기기 검증 전에는 물리 완료 통합 완료로 보고하지 않는다.

8. 검증 수준

최초 설계 단계는 위 파일과 테스트 본문을 읽은 정적 원본 분석이었다. 이후 원본 JVM 실행 결과는 1절에 추가했다. 최초 분석에서는 MR6 테스트를 실행하거나 실기기에서 경쟁·timeout을 재현한 것은 아니다. 이전 Evidence 단계의 JVM 167/37 통과를 이 신규 Coordinator 설계의 검증으로 재사용하지 않는다.

Connections

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