Skip to content

v0.2.18 — 세션이 만료되면 grok은 기다리지 않는다

Choose a tag to compare

@xzawed xzawed released this 05 Sep 00:52
· 18 commits to main since this release
80d2aed

v0.2.18 — 세션이 만료되면 grok은 기다리지 않는다, 그리고 우리는 정반대를 안내했다

2026-09-05. 오래 이월되던 마지막 두 항목은 오너 입력 대기로 적혀 있었다. 둘 다 물어보지
않고 실측으로 닫았고, 그 과정에서 사용자에게 보이는 실제 결함 하나가 나왔다.


1. GUI 슬래시 커맨드 칸 — serverVersion: 0.2.17 (닫힘)

재시작된 세션에서 플러그인이 띄운 MCP 서버의 grok_build_status(= /grok:status의 구동부)가
ready: true · billing: subscription · serverVersion: 0.2.17 을 반환했다. 마켓플레이스
설치본이 실제로 로드돼 돌고 있다는 뜻이고, 갱신 시점에 물고 있던 0.2.11 프로세스는 재시작으로
사라졌다. docs/09 §5에 열린 칸은 이제 없다.

2. 만료 세션 — 답은 "폐기"다 (닫힘, 사람 캡처 불필요)

문서는 "만료면 grok이 device-OAuth를 stderr로 내고 블록하므로 래퍼 timeout이 된다"고
적고 있었다 (2026-07-13 관측). 오너가 만료되는 순간을 붙잡아 캡처해 줘야 닫히는 항목이었다.

그럴 필요가 없었다. 만료는 세션의 부재가 아니라 auth.json이 있는데 거부되는 경우이고,
그건 격리 GROK_HOME합성 auth.json을 써서 재현할 수 있다 (실 ~/.grok은 읽지도 쓰지도
않는다). npm run probe:expired가 그것이고, 3회 연속 같은 결과를 냈다 — 1.0.13, win32:

변형 auth.json 결과
C1 expires_at 과거 + 갱신 실패 exit 1 · Not signed in.
C2 expires_at 미래 + 서버가 거부 exit 1 · Unauthorized (401) … Invalid or expired credentials
B (대조군) 파일 없음 exit 1 · Not signed in.

어떤 변형도 기다리지 않는다. device-OAuth 마커는 어디에도 없고, 첫 출력까지 10~20초, 전부
exit 1이다. 옛 A 경로는 1.0.13에서 재현되지 않았다(신호는 보험으로 남겼다).

3. 그래서 발견된 결함 — 만료 순간 우리는 "로그인할 필요 없다"고 안내했다

C2 봉투에는 AUTH_ERROR_SIGNALSDEVICE_AUTH_SIGNALS하나도 매칭되지 않는다.
not signed ingrok login도 없기 때문이다. 대신 xAI의 상용구가 이렇게 끝난다:

Your session is still signed in and will recover automatically — retry in a few seconds;
no need to run /login.

그래서 runDelegate는 이 실행을 auth_error가 아니라 grok_error 로 분류했고, 그 문장이
그대로 사용자 안내가 됐다. 즉 구독 세션이 죽는 바로 그 순간에, 플러그인은 사용자에게
"재로그인할 필요 없다"고 말하고 있었다. 실측으로 고정한 관측값:

r.status  = "grok_error"
AUTH_ERROR_SIGNALS hits   = []
DEVICE_AUTH_SIGNALS hits  = []
message contains "no need to run /login" = true

이 관측은 Grok이 독립적으로 작성한 테스트로 재현했다 — 같은 값이 나왔다.

고친 것. AUTH_ERROR_SIGNALS/invalid or expired credentials/i 한 줄. 상태코드가 아니라
자격증명 문구를 매칭한다 — "광범위한 401/403은 제외한다"는 기존 결정은 그대로다. 회귀 테스트
3건이 붙었다: 401 봉투 → auth_error + grok login 안내 + 그 상용구가 안내로 새지 않을 것,
자격증명 문구 없는 맨 401은 여전히 grok_error.

4. 액세스 토큰 수명은 7일이 아니라 6시간이다

docs/02는 "공개 문서상 약 7일로 추정 — 미검증"이라고 적고 있었다. 값이 아니라 시간 차이만
계산해 실측했다: expires_at − create_time = JWT exp − iat = 6.00시간, 그리고 expires_at
그 JWT의 exp와 같다. 사용자가 6시간마다 로그인하지 않는 이유는 별도의 refresh_token이 조용히
갱신하기 때문이다. 리프레시 토큰 수명은 여전히 미측정이고, grok login을 부르는 것은 그쪽이다.

5. 프로브가 조용히 무의미해질 뻔한 지점

처음 커밋한 probe:expired는 세 변형이 전부 B("Not signed in")로 무너졌다 — 즉
probe:unauth의 사본이었다. 원인은 auth.json 항목 키를 익명화한 것이다. 그 키는
<oidc_issuer>::<oidc_client_id>이고, UUID는 항목의 oidc_client_id와 같다 — 사용자 id가
아니라 grok CLI의 OAuth 클라이언트 id
(모든 설치본에서 동일, 공개값)다. 다른 UUID를 쓰면 CLI가
자기 클라이언트의 항목을 찾지 못한다. 실제 파일의 필드와 대조해서야 잡혔고, 스크립트에 주석으로
박아뒀다. 프로브는 "돌았다"가 아니라 대조군과 달라야 의미가 있다.


바뀐 것

영역 변경
src/delegate.ts AUTH_ERROR_SIGNALSinvalid or expired credentials 추가 + 실측 근거 주석
test/delegate.test.ts 회귀 3건 (401 봉투 분류 · 자격증명 문구 · 맨 401 비매칭)
scripts/probe-expired-session.mjs 신규. npm run probe:expired
docs/specs/grok-cli-contract.md §7 경로 C 신설, §7 행 2026-09-05로 갱신
docs/02-auth-strategy.md 만료 체크박스 닫음, 토큰 수명 6시간으로 정정, 신호 목록 갱신
docs/09-scope-and-residuals.md §5 마지막 칸 닫음
CLAUDE.md 컴포넌트 지도의 "만료 = 블록 → timeout" 서술 정정, 핸드오프 갱신