ACP extension watcher: 첫 세션 측정
이 변경 사항은 ACP 프로세스에서 대화형 extension 파일 watcher를 건너뜁니다. 데몬은 이미 자체 리소스 새로 고침 라이프사이클을 소유하고 있습니다. 대화형 터미널 세션은 계속 watcher를 생성합니다. 이것은 첫 세션 최적화의 첫 번째 단계이며, 500ms 미만의 첫 새 세션을 확립하는 것이 아닙니다.
변경 사항 및 출처
기준선은 main 커밋 2985fef4e9b9393601141c16031b2ba039181158이고, 측정된 후보는 watcher 전용 커밋 2aadc4b127ec24074e0e5ddfd402e978a0c43f5d입니다. 프로덕션 변경 사항은 하나의 추가 ACP 모드 가드입니다. --acp와 --experimental-acp가 모두 포함되며, 대화형 모드에 대해 watcher를 생성하는 제어 항목도 함께 포함됩니다. Core 초기화, 리소스 선택, 프롬프트, 인증, MCP 정책 또는 프리히트 구현 변경 사항은 포함되지 않습니다.
두 번들 모두 CLI 버전 0.27.2를 사용합니다. 호출하는 TypeScript 패키지는 @qwen-code/sdk 0.1.32입니다. 각 실행 전후에 패키지 버전과 SDK 진입 해시가 기록되었습니다. 완전한 기준선, 후보 및 컴파일된 SDK 파일 트리 다이제스트도 고정되어 측정 코호트 주변에서 확인되었습니다. 후보는 고정된 pnpm 11.24.0 lockfile 설치, 전체 빌드, 타입체크 및 번들로 독립적인 worktree에서 빌드되었습니다.
워크로드 및 타이밍 경계
비공개 설치된 워크로드에는 31개의 리소스가 포함되어 있습니다: 14개의 extension 스위트와 17개의 독립 실행형 Skill, 90개의 커스텀 Skill, 3,944개의 파일, 81,931,741바이트. 모든 샘플은 대소문자를 구분하는 로컬 파일 시스템에 동일한 완전한 리소스 목록을 구체화합니다. 리소스 이름, 소스 파일, 비즈니스 콘텐츠, 매니페스트, 로컬 경로, 식별자 및 원시 로그는 비공개로 유지됩니다. 여기에는 집계 카운트와 타이밍만 게시됩니다.
프로파일은 hook을 유지하고 MCP 허용 목록을 빈 목록으로 설정합니다. 프롬프트, 모델 요청 또는 비즈니스 도구 호출을 보내지 않으며 구성된 외부 MCP 서버에 연결하지 않습니다. 설치된 네이티브 활성화 상태는 타임아웃이 없는 픽스처 준비 중에 시딩됩니다. 이것은 이미 설치 및 활성화된 리소스 세트를 나타내며, 새 프로세스와 새 세션 상태를 가집니다; 모든 리소스 파생 캐시가 비어 있다고 주장하는 것은 아닙니다. 픽스처 생성, 파일 복사, 네이티브 활성화 시딩, 번들 빌드 및 SDK 모듈 가져오기는 두 시계 중 어느 쪽이 시작되기 전에 완료됩니다.
각 샘플은 새로운 HOME, 런타임 디렉토리, TMPDIR, 영구화된 세션 루트 및 초기에 비어 있는 Node 컴파일 캐시 디렉토리를 가집니다. 데몬은 preheatBridge: false로 실제 임베디드 HTTP 브리지 진입점을 통해 시작됩니다. 드라이버는 runtimeReady를 기다린 다음 첫 SDK 호출 전에 비즈니스 세션이 0개이고 활성 ACP 채널이 없음을 확인합니다. 해당 호출 이전에 HTTP 준비 상태 또는 기능 요청이 없습니다. 새 UUID가 새 스레드를 요청하며; 결과는 attached: false로 이를 반영해야 합니다. 두 개의 추가 새 UUID 호출이 후속 세션 동작을 검증합니다.
준비 요청 경계는 SDK 클라이언트 생성 및 호출자 UUID 생성 이전에 관찰됩니다; 둘 다 기본 create 시계 외부에 있습니다.
기본 시계는 완전한 await client.createOrAttachSession(...)을 포함합니다: 기능 검색, 세션 POST, 응답 JSON 파싱 및 SDK ID 검증. 첫 HTTP 요청은 GET /capabilities이며; 그 단독 지속 시간은 새 세션 측정이 아닙니다. 요청 기록은 세 호출 모두에 대한 실제 순서를 유지합니다; 이후 호출에서 기능 확인이 생략된다고 가정해서는 안 됩니다.
보고서는 또한 세션 POST, 데몬 프로세스 스폰에서 데몬 준비 요청 경계까지, 그리고 데몬 스폰에서 첫 완료된 SDK 결과까지를 노출합니다. 데몬 대기로는 ACP 프로세스가 생성되지 않습니다: 기록된 모든 ACP 스폰은 SDK 호출 시작과 첫 HTTP 요청 이후에 발생해야 합니다. 데몬 상태는 프리히트 not_scheduled를 보고해야 합니다. 공식 샘플에 CPU 프로파일러, 명시적 컴파일 캐시 플러시, 비활성화된 자식 컴파일 캐시, 인위적 슬립 또는 시작 프롭이 표시되지 않습니다.
공식 결과
첫 완전한 SDK create가 중앙값에서 1096.1ms에서 772.9ms로 감소합니다: 323.2ms / 29.48% 낮아짐. 후보는 모든 샘플에서 500ms를 초과합니다.
아래 모든 값은 밀리초이며, 조건당 8개의 독립적인 첫 세션을 가진 중앙값(최소–최대)으로 표시됩니다. 두 조건 모두 8/8 시도를 완료하여 24/24 새 세션을 생성합니다. 공식 샘플은 제외되지 않습니다.
| 시계 | 기준선 | Watcher 전용 |
|---|---|---|
| 첫 완전한 SDK create (기본) | 1096.1 (1078.3–1129.3) | 772.9 (758.4–824.1) |
| 첫 세션 POST + JSON | 1075.7 (1058.8–1109.2) | 754.1 (739.3–798.5) |
| 데몬 스폰 → 관찰된 리스너 | 336.7 (322.5–341.5) | 329.2 (323.1–358.5) |
| 데몬 스폰 → 준비 요청 경계 | 630.6 (618.7–644.5) | 605.3 (591.8–621.0) |
| 데몬 스폰 → 첫 SDK 결과 | 1731.0 (1709.6–1748.0) | 1384.5 (1355.5–1427.0) |
| 첫 capabilities GET + JSON | 18.7 (17.7–28.1) | 18.3 (18.1–25.1) |
| 첫 HTTP → ACP 스폰 | 14.2 (13.9–22.3) | 14.2 (14.1–24.6) |
| 두 번째 완전한 SDK create | 71.1 (65.1–79.6) | 74.0 (65.2–80.0) |
| 세 번째 완전한 SDK create | 56.9 (53.7–63.7) | 54.4 (53.4–56.6) |
쌍별 라운드의 첫 create 샘플:
| 라운드 | 기준선 | Watcher 전용 |
|---|---|---|
| 1 | 1098.5 | 758.4 |
| 2 | 1078.3 | 771.1 |
| 3 | 1129.3 | 807.8 |
| 4 | 1110.2 | 760.1 |
| 5 | 1082.6 | 767.9 |
| 6 | 1089.2 | 774.8 |
| 7 | 1093.7 | 789.0 |
| 8 | 1110.5 | 824.1 |
공개 숫자 요약에는 모든 공식 샘플, 평균, 중앙값, 범위, 컴파일/빌드 트리 다이제스트 및 통과/실패 카운트가 포함됩니다. 명시적 허용 목록에서 구성되며 비공개 리소스 목록, 소스 콘텐츠, 로컬 경로, UUID, 토큰 또는 원시 로그를 포함하지 않습니다.
이전 6회 시도 코호트는 임시 픽스처 볼륨의 공간이 부족하여 중단되었습니다(5개의 완료된 샘플과 1개의 세션 초기화 실패). 실패 로그에는 런타임 디렉토리 생성 시 ENOSPC가 포함되어 있습니다. 6개 프로세스 모두 정상적으로 종료되었으며 전체 코호트는 완료된 타이밍을 포함하여 제외됩니다. 더 큰 독립적인 대소문자 구분 볼륨과 16개의 완전히 새로운 픽스처가 공식 코호트를 재시작하기 전에 준비되었습니다. 실패한 증거는 로컬에 보관되며 결과에 조용히 재시도되지 않습니다.
8개의 쌍별 라운드가 A/B 다음 B/A 순서로 교대로 직렬 실행되었습니다. 모든 픽스처는 배타적 측정 창 이전에 준비되었습니다. 이 작업 아래에서 빌드, 픽스처 복사, 다른 벤치마크 또는 테스트가 동시에 실행되지 않았습니다. OS 파일 캐시는 삭제되지 않았습니다; 이것은 콜드 디스크 측정이 아닌 한 호스트에서의 새 프로세스, 새 세션 측정입니다. 조건당 8개의 샘플은 프로덕션 꼬리 지연 보장을 설정하기에 너무 적습니다.
호스트: macOS 26.6.2, arm64; Node.js v26.7.0. 이 로컬 격리 재구성은 비공개 프리프로덕션 설치 목록을 사용하며 프로덕션 또는 라이브 프리프로덕션 지연 측정이 아닙니다. 500ms 목표는 첫 완전한 SDK create에 적용되며 이 PR 이후의 후속 작업으로 남아 있습니다.
기능 검증 및 한계
별도의 기능 실행은 동일한 완전한 설치된 목록으로 고정된 기준선과 watcher 전용 번들을 비교합니다. 이들은 공식 타이밍 코호트의 멤버가 아닙니다: 일부 기능 확인 전에 헬스 및 헬퍼 호출이 선행됩니다.
- 두 조건 모두 41/41 외부 변경 어설션과 18/18 활성화/라이프사이클 어설션을 통과합니다.
- 8개의 헬퍼 스냅샷, 헬퍼 이후의 8개 기존 세션 메뉴, 8개의 새로 생성된 세션 메뉴 및 11개의 라이프사이클 스냅샷이 픽스처 경로 및 UUID 대응 이후에 일치합니다.
- 일반 읽기는 관찰된 전파 차이를 보존합니다: 완전한 워크스페이스-Skill 엔벨로프가 29/32 샘플에서 일치하고, Skill 콘텐츠가 31/32에서, 기존 세션 명령 목록이 31/32에서 일치합니다. 하나의 관찰에서 후보에서 원자적 치환이 더 일찍 나타나고; 파일 재생성이 기준선에서 더 일찍 잠깐 나타납니다. 이후 샘플 또는 일반 헬퍼가 수렴합니다. Extension Skill 편집/복원은 3초 관찰 창 동안 두 조건 모두에서 오래된 상태로 유지되며 헬퍼 이후에 정확해집니다.
- 양쪽 모두 동일한 타입/위상 시퀀스로 8개의 공개 SSE 이벤트를 내보냅니다. 첫 7개의 해당 페이로드가 일치하며; 마지막 리로드 페이로드는 다른 완료 순서로 동일한 9개 세션을 새로 고칩니다. 동일성을 확인할 때 원래 배열 순서가 유지됩니다.
- 새 세션 응답은 UUID, 생성 시간 및 클라이언트 ID에서 자연스럽게 다릅니다. 다른 응답 필드는 일치하며; 실제 생성은 UUID 반향 및
attached: false로 독립적으로 어설션됩니다.
픽스처 및 번들 루트, 해당 루트에서 파생된 워크스페이스 식별자 및 UUID 대응만 정규화됩니다. 별도로 보고된 워크스페이스-Skill 비즈니스 비교의 경우 관찰 타임스탬프 및 연령이 제외되며; 원시 엔벨로프는 그대로 유지됩니다. 캐시 오래됨, 새로 고침 플래그, 활성화 상태, 생성, 모든 Skill/명령 필드 및 원래 배열 순서는 동일성을 만들기 위해 지워지지 않습니다. 이러한 관찰은 동일한 전파 지연 또는 바이트 단위로 동일한 일반 읽기를 증명하지 않습니다.
모든 기능 그룹은 정상 종료 확인을 받고 코드 0, 시그널 없음, 강제 폴백 없이 종료됩니다. 최종 범위 OS 관찰에서 일치하는 벤치마크 프로세스가 발견되지 않습니다. 공식 타이밍 샘플은 자체 정상 종료 확인, 0 종료 상태, 강제 폴백 없음 및 기록된 모든 ACP 자식 PID 소멸을 별도로 적용합니다.
집중 CLI 단위 스위트가 129/129를 통과하며, 전체 빌드, 타입체크, 번들, 변경 파일 ESLint 및 Prettier 확인이 통과됩니다. 대화형 watcher 생성은 단위 제어로 검증되며; 대화형 터미널 UI 종단 간 실행, Windows, Linux, 모델 실행, 프롬프트에서 실행되는 hook 및 외부 MCP 동작은 이 검증 범위 밖에 있습니다.
공개 합성 리소스로 재현
공개 생성기는 비공개 설치를 읽거나 내보내지 않고 제네릭 리소스를 작성합니다. 14개의 스위트, 17개의 독립 실행형 Skill 및 90개의 Skill 매니페스트를 사용하지만 바이트, 디렉토리 형태, 독립 실행형 Skill 배치, hook 정의 및 활성화 준비가 다릅니다. 해당 타이밍은 절차를 재현하고 스케일링 동작을 노출할 수 있지만 위의 비공개 워크로드 숫자를 재현하거나 대체할 수 없습니다.
corepack pnpm install --frozen-lockfile, npm run build 및 npm run bundle를 사용하여 각 커밋에서 고정된 기준선과 고정된 후보를 빌드합니다. 공개 재현은 Node.js v26.7.0으로 확인되었습니다. SDK 빌드를 고정하고, 측정 전에 빌드 및 리소스 복사를 중지하고, 두 번들을 직렬로 교대합니다. 이 체크아웃에서 새 출력 디렉토리당 하나의 샘플을 실행합니다:
node scripts/benchmarks/acp-first-session/fixture.mjs /tmp/acp-synthetic-a /absolute/frozen-baseline/dist
node scripts/benchmarks/acp-first-session/fixture.mjs /tmp/acp-synthetic-b /absolute/frozen-candidate/dist
node scripts/benchmarks/acp-first-session/run.mjs /tmp/acp-synthetic-a/fixture.json
node scripts/benchmarks/acp-first-session/run.mjs /tmp/acp-synthetic-b/fixture.json측정 코호트 전에 모든 새 픽스처를 준비합니다. 새 합성 스모크는 3개의 create 모두와 no-preheat, ID, 종료, 자식 종료 및 기록된 입력 해시 확인을 완료합니다. 절차를 검증하고 비공개 결과에 샘플을 기여하지 않습니다. 각 실행은 경로 없는 숫자/부울 요약을 인쇄하고 요청된 출력 위치에 자세한 로컬 증거를 보관합니다. 합성 리소스에는 SessionStart hook이 포함되어 있지 않으며; 프롬프트가 전송되지 않으므로 작성된 UserPromptSubmit hook은 실행되지 않습니다. 최소 8개의 교차 쌍을 사용하고, 실패를 유지하고, 모든 프리히트/세션/스포/종료 어설션을 검사하고, 모든 시계를 보고하십시오. 로컬에서 생성된 픽스처 트리 또는 원시 결과를 커밋하지 마십시오.
종료 후에도 기록된 ACP PID가 여전히 존재하면 공개 러너는 결과를 실패로 표시하고 수동 검사를 위한 정리 오류를 기록합니다. PID 재사용은 프로세스 ID를 증명하는 것을 방지하므로 자동 종료는 자체 래퍼 프로세스 핸들로 제한됩니다.
남은 500ms 미만 작업은 동일한 no-preheat 경계 및 기능 확인으로 첫 SDK 호출 이후에 수행되는 초기화를 줄여야 합니다. 이것은 이 한 줄 watcher 변경과 의도적으로 분리되어 있습니다.