공통 Rust CLI에서 등록된 단계를 실행하면 기존 실행기가 작업을 맡고, 돌아온 작업 ID로 상태와 로그를 확인한다. 브라우저의 MCP 연결도 원래 명령과 실행 호스트를 재사용했다. 입구를 늘리면서 입력 검사와 실행 기록을 원래 프로그램에 남긴 사례다.
브라우저 MCP와 공통 CLI는 서로 다른 엔진을 쓰지만, 새 입구에 실행 책임을 다시 만들지 않았다는 점이 같다. 각 프로그램의 검사와 기록을 어디에 남겼는지 비교했다. 공통 CLI의 전체 연결 Goal은 이 자료를 읽은 당시에도 진행 중이었다.
영상편집기에서는 이름으로 고를 때 적용되던 검사가 요소 번호 경로에서 빠져 있었다. 수정은 두 경로가 실제 대상을 찾은 뒤 같은 검사를 거치게 했다. 아래에서는 그 호출 순서와 시점별 검증 범위를 함께 살펴본다.
두 입구가 두 제품이 되지 않게 한다
화면에서는 비활성 플러그인을 실행할 수 없는데 MCP에서는 ID만 알면 실행된다면 같은 기능이라고 보기 어렵다. 한쪽은 결과를 검증하고 다른 쪽은 프로세스 시작만 성공으로 보아도 문제가 생긴다. 사용자는 어느 입구로 요청했느냐에 따라 다른 규칙을 경험한다.
그래서 외부 제어기를 기존 프로그램·노트북·컨트롤러 서비스에 연결했다. MCP의 전달 형식은 달라도 작업 소유권과 활성화 상태, 실행 중 여부를 확인하는 책임은 유지한다. UI 문구를 그대로 복사하는 것보다 중요한 공통점은 실제 실행에서 같은 보호가 적용되는지였다.
플러그인 실행은 기존 명령으로 이어진다
외부 handler는 먼저 현재 context를 확인하고 목록을 갱신한 뒤 선택한 플러그인이 활성 상태인지 본다. 실행할 때는 기존 pluginRun 명령에 프로젝트·프로필·탭·입력과 실행 방식을 전달한다. MCP 전용으로 Python을 직접 띄우는 별도 지름길을 만들지 않는다.
발행과 전달의 단순 입력도 기존 pluginPublish와 pluginDeliver 명령으로 이어진다. 명령 내부의 저장 기본값과 파일 선택, 실행 전 조건을 그대로 만나게 하려는 구조다. 같은 이름의 새 함수가 있다고 공통 엔진인 것은 아니므로 실제 주입된 command와 호출 경로까지 읽어 확인했다.
수동 조작도 Broker를 통과한다
northstar_call은 현재 taskId인지 확인한 뒤 programCall을 사용한다. TaskController의 programCall은 broker.execute에 현재 실행 세대를 넘긴다. 에이전트가 요청했다고 네이티브 입력이나 요소 참조 검사를 건너뛰는 경로가 아니다.
MCP에서 임의 페이지 자바스크립트나 CDP 명령을 직접 보내지 않는 이유도 여기에 있다. 고정 도구를 통해서만 현재의 대상 선택과 결과 검증을 이어 간다. 호스트 내부에 브라우저 제어 기술이 있다는 사실과 외부 호출자에게 그 기술의 모든 명령을 공개한다는 것은 다른 설계다.
공통 경로 위에서도 외부 입력은 검사한다
공통 서비스를 쓴다고 외부 입력의 검사가 없어지지는 않는다. 스키마와 문맥, 현재 taskId, 비공개 프로필과 활성 플러그인 같은 조건을 입구에서 확인한다. 이미 실행 중인 프로그램이나 노트북과 충돌하는 요청도 거절한다.
공통 실행 통로와 입구별 검사는 함께 필요하다. 화면의 클릭과 외부 메시지는 도착 경로가 달라 공통 서비스에 넘기기 전의 조건도 다를 수 있다. 모든 코드를 한 함수에 넣기보다 실행 책임은 모으고 각 입구에 필요한 검사를 두는 방식이다.
실행 성공과 자동 보관도 구별했다
finishProgram에는 정상 작업의 반복 절차를 보관하는 경로가 있다. 자동 보관이 실패하면 이벤트를 남기고, 그 일과 실제 실행 결과의 상태를 구별한다. 정상 작업 결과와 재사용 자산 생성이 항상 같은 순간에 성공하는 것은 아니다.
관련 통합 시험은 비활성 플러그인과 다른 문맥을 거절하고 미확정 결과가 있는 작업을 완료로 만들지 않는지 본다. 기존 제작기는 당시 호출 경로와 시험 코드를 대조한 기록이다. 이번 보완에서 운영 앱을 조작하거나 모든 UI 버튼과 MCP 명령의 완전한 동등성을 전수 시험하지는 않았다.
Rust로 만든 입구와 원래 실행 엔진을 구분한다
공통 CLI는 Rust로 프로그램 정의와 기존 실행 기록을 읽는다. 그러나 등록된 단계의 실행은 고정된 Python 호환 연결을 거쳐 기존 tower.cli_run에 위임한다. 명령을 받는 프로그램이 Rust라는 사실과, 연결된 프로그램의 내부 엔진까지 Rust로 바뀌었다는 주장은 다르다.
이 연결층은 등록 프로그램과 단계를 찾고 허용된 입력 이름을 검사한다. 원래 단계에 확인 조건이 있으면 그대로 요구하며, 설치된 CLI가 그 확인을 대신 승인하지 않는다. plan 경로는 실행 사양과 인자 개수를 보여 주되 인자 값은 드러내지 않고 executed를 false로 반환한다. 사양을 확인한 결과를 업무 실행 결과로 바꾸지 않는다.
실행과 로그를 맡는 별도 관리자도 만들지 않는다. 관제탑 작업은 기존 실행기의 run_id로, API 작업은 반환된 job_id로 조회한다. 대기 시간이 끝나도 원래 작업을 자동 취소로 바꾸지 않는 경로가 있다. 같은 CLI에서 조회하더라도 작업을 소유한 엔진과 ID의 종류는 함께 읽어야 한다.
연결 현황에는 등록과 검증의 차이를 남긴다
coverage 소스는 프로그램 목록을 단순히 연결 완료 숫자로 바꾸지 않는다. 실행기를 찾지 못한 단계, 대상 경로가 없는 단계, 등록만 된 단계, 파일이나 화면을 여는 단계, 과거 성공 기록이 있는 단계를 나누어 표시한다. 캐시에 저장된 연결 검사 시각도 별도로 남긴다.
과거 성공 표시는 해당 프로그램·단계에 완료 상태와 정상 종료 코드가 남은 실행 기록을 찾는다. 지금 모든 기능이 동작한다는 검사가 아니다. 읽은 함수는 전체 연결·검증 완료 값도 false로 둔다. 정의를 찾았는지, 화면을 열었는지, 요청한 업무가 끝났는지를 나눠 읽을 수 있게 한 것이다.
격리 시험 소스에는 기존 확인 조건의 유지, 알 수 없는 입력 거절, 미리보기에서 변경 요청을 보내지 않는 조건, 비동기 작업 ID 유지와 대기 만료가 있다. 이번에는 이 선언과 코드를 읽었으며 원래 시험·CLI·API를 실행하지 않았다. 앞선 브라우저 사례와 함께 재사용할 것은 실행 입구를 늘릴 때 원래 검사·기록·작업 소유를 어디에 남길지 정하는 기준이다.
이름과 번호로 찾은 뒤 같은 선택 검사를 거친다
영상편집기를 CLI로 연결한 뒤 사용자는 캐릭터·화자 선택까지 기능을 넓혀 달라고 요청했다. 이때 선택 항목을 이름으로 지정할 수도 있고, 관찰한 화면의 요소 번호로 지정할 수도 있다. 번호가 존재한다는 확인만으로 그 요소를 선택 항목이라고 받아들이면 선택창의 확인·합성 같은 동작 버튼도 들어올 수 있다.
수정 기록에는 번호 경로가 이름 경로의 동작 문구 검사를 건너뛰었다고 남아 있다. 판독 시점의 choose 함수는 이름을 실제 요소 번호로 해석하거나 입력된 번호를 받은 뒤 공통 validate_choice_target을 호출한다. 이 검사를 통과해야 화면 조작 함수로 넘어간다. 이름과 번호는 대상을 찾는 방법이고, 그 대상이 선택 명령의 범위에 드는지는 함께 검사한다.
두 경로 모두 앞에서 현재 스냅샷과 선택 패널을 확인한다. 화면 조작 함수도 입력 직전에 관찰을 다시 대조한다. 여기의 요소 번호는 그 스냅샷 안에서 읽은 번호다. 앱 업데이트나 화면 변경을 넘어 같은 선택지를 가리키는 고정 카탈로그 ID처럼 보관해 쓰는 값으로 설명하지 않았다.
코드와 구현 살펴보기
확인한 호출 순서의 설명도 · 실행 모듈 아님
verify snapshot + selection panel
--name -> resolve node in that snapshot
--id -> use node from that snapshot
both -> validate target + actionable ancestors
-> UI action with snapshot revalidation
-> new observation; selection_applied_verified = false이름 없는 그림은 부모의 동작까지 확인한다
확인 버튼 안의 그림 요소에는 이름이 없을 수 있다. 대상의 이름만 검사하면 빈 이름은 통과하고, 실제 클릭은 그 버튼의 동작으로 이어질 수 있다. 확인한 함수는 선택한 요소와 조작 가능한 선조의 문구를 함께 살핀다. 입력창·비밀번호 요소, 범위를 벗어난 번호, 잘못된 부모 관계도 거절한다.
확인한 규칙은 확인·합성·생성·삭제 같은 문구와 일부 적용 표현을 선택 동작에서 제외한다. 모든 상위 요소의 프로젝트 제목까지 금지어로 검사하는 구조는 아니다. 대상과 특정 조작형 선조에 적용한 문구 규칙이므로, 모든 언어와 새 버전의 동작 의미를 이해하는 범용 판별기로 보아서는 안 된다.
코드 안의 회귀 함수는 보통 화자 이름의 요소를 허용한다. 확인 버튼과 그 안의 이름 없는 이미지, 다른 동작 문구, 없는 번호와 편집 가능한 요소는 거절하는 조건이다. 첫 기록의 전체 5개 검사·빌드와 후속 기록의 전체 8개 검사를 시점별로 구분했다. 이번에는 기록과 함수 정의를 읽었으며, 이 함수 시험만으로 이름·번호 명령을 실제 화면에서 모두 검증했다고 쓰지는 않았다.
선택 명령의 결과도 적용 확인값을 false로 남기고 새 관찰을 돌려준다. 캐릭터 타일은 선택만으로 클립에 들어갈 수 있고, 화자 선택과 실제 합성은 다른 단계다. 후속 기록에는 일부 선택 패널의 실제 화면 확인도 추가됐다. 모든 조건부 항목과 합성·내보내기 결과까지 확인한 것은 아니며, 공통 코드의 독립 검수도 미확인으로 남아 있다.
다른 업무 도구에도 같은 질문을 한다
대표 화면과 직원 화면, 관리자 API와 자동화 CLI가 함께 있는 업무 프로그램에도 같은 문제가 있다. 화면을 여러 개 만드는 일보다 실제 저장·검증·권한의 기준이 어디에 모이는지 먼저 정해야 한다. 한 입구만 빠르게 동작하는 것이 전체 완성도는 아니다.
기존 실행 규칙을 재사용하면 입구마다 규칙이 달라질 여지를 줄일 수 있다. 다만 공통 코드의 오류도 여러 입구로 퍼질 수 있어 회귀 시험이 필요하다. 같은 경로를 호출한다는 코드 근거와 그 경로로 특정 업무를 끝냈다는 실행 근거를 따로 남겨야 한다.