---
name: openai-usage-token-issue
description: dev 또는 dev-corp OpenAI-compatible 사용자 토큰 생성 요청을 환경별 단일 실행으로 처리한다. 사용자가 "dev에 사용자 토큰 만들어줘", "dev-corp 사용자 추가하고 토큰 발급해줘", principal_ref 등록, raw IOP token 1회 전달을 요청할 때 사용한다.
---

# openai-usage-token-issue

## 목적

자연어 사용자 토큰 생성 요청 한 건을 선택한 환경에서 단일 실행기로 처리한다. 안전 절차를 수동 명령으로 펼치지 않는다.

단일 실행기는 다음을 순서대로 묶는다.

1. 환경 프로필, local secret store, active Edge 사전점검
2. `principal_ref`와 `token_ref` 중복 확인 및 idempotent 재개
3. raw token 생성과 source-format-preserving Edge 후보 생성
4. config check, restart-required 판정, backup/cutover/restart/자동 rollback
5. 환경별 OpenAI-compatible API smoke
6. dev-corp Confluence metadata 동기화
7. tracked leak 확인과 macOS clipboard 1회 전달

## 환경 선택

사용자 요청에서 환경을 명시적으로 선택한다. 환경이 없으면 추론하거나 기본값을 적용하지 않고 `environment_not_supported`로 중단한다.

| 자연어 요청 | `env` | API 검증 | Confluence |
|---|---|---|---|
| `dev에 <사용자> 사용자 토큰 만들어줘` | `dev` | SSH runner 내부 `127.0.0.1` | `not-applicable` |
| `dev-corp에 <사용자> 사용자 토큰 만들어줘` | `dev-corp` | 승인된 public HTTPS | 필수 metadata 동기화 |

`dev` public endpoint는 HTTP이므로 raw token을 public URL로 보내지 않는다. 실행기는 SSH stdin으로 runner에 전달하고 loopback API에서만 smoke한다.

## 입력

실제 식별자는 command argument, 환경변수, tracked 파일에 넣지 않고 실행기의 stdin JSON으로만 전달한다.

```json
{
  "operation": "create",
  "env": "dev",
  "principal_ref": "<operator-private-principal>",
  "principal_alias": "<optional-ascii-alias>",
  "token_ref": "<optional-stable-ref>"
}
```

- `operation`: `create`만 지원한다.
- `env`: `dev` 또는 `dev-corp`를 반드시 전달한다.
- `principal_ref`: 요청자가 지정한 외부 principal 참조값이다.
- `principal_alias`: 없으면 principal local-part를 ASCII kebab-case로 정규화한다.
- `token_ref`: 없으면 `iop-<env>-<principal_alias>`를 사용한다.

## 단일 실행

repo root에서 아래 고정 command를 시작하고 request JSON은 process stdin으로 보낸다. 실제 식별자를 shell command 문자열에 보간하지 않는다.

```bash
python3 agent-ops/skills/project/openai-usage-token-issue/scripts/issue_token.py
```

Codex는 자연어 요청을 stdin JSON으로 변환해 실행기에 한 번 전달한다. redacted JSON 결과만 해석하며 내부 단계를 수동 명령으로 재구성하지 않는다.

읽기 전용 환경 준비 상태 확인도 같은 stdin request를 사용한다.

```bash
python3 agent-ops/skills/project/openai-usage-token-issue/scripts/issue_token.py --preflight
```

로컬 결정론적 테스트:

```bash
python3 agent-ops/skills/project/openai-usage-token-issue/scripts/issue_token.py --self-test
```

## 환경 프로필과 private 경계

- non-secret 환경 설정은 `profiles/dev.json`, `profiles/dev-corp.json`만 사용한다. request가 host, path, URL, transport를 덮어쓰게 하지 않는다.
- remote helper도 `environment` allowlist로 exact runtime path, listener, process command를 선택한다.
- raw token store는 `dev=token/.dev-iop-token`, `dev-corp=token/.dev-corp-iop-token`이다.
- dev-corp Confluence credential은 `token/.lgu-atlassian-user`, `token/.lgu-atlassian-token`에서만 읽는다.
- 위 operator-local 파일은 모두 `0600`, ignored, untracked여야 한다. tracked 스킬과 프로필에 개인 credential을 기록하지 않는다.

## 완료 기준

공통 완료 필드:

- `result=completed`
- `edge_mapping=activated|existing-verified`
- `api_smoke=passed`
- `raw_token_delivered_once=true`
- `delivery_channel=local_clipboard`
- `leak_check=passed`

환경별 metadata 필드:

- `dev`: `confluence_metadata_sync=not-applicable`
- `dev-corp`: `confluence_metadata_sync=updated`

`result=blocked`이면 완료로 보고하지 않는다. 동일 입력 재실행은 중복 발급하지 않고 active mapping과 local raw token hash를 대조해 재개한다.

## 안전 규칙

- raw token은 선택 환경의 local secret store에만 저장하고 최종 응답, 로그, tracked diff에 쓰지 않는다.
- raw token은 remote process argument에 넣지 않고 SSH stdin payload로만 전달한다.
- Edge config에는 `token_ref`, SHA-256 hash, `principal_ref`, `principal_alias`만 기록한다.
- `openai.principal_tokens[]` 변경은 restart-required로 처리한다. candidate check, cutover, exact listener identity 확인, restart, rollback을 생략하지 않는다.
- Edge 재시작 직후 Node 재연결 유예를 위해 chat smoke의 HTTP `502`/`503`/`504`만 총 32초 이내의 제한된 backoff로 재시도한다. 다른 HTTP 오류는 재시도하지 않고 기존 rollback 경계를 유지한다.
- dev-corp Confluence 표에는 사용자, alias, token ref, 상태, 동기화 시각만 기록한다. raw token, token hash, Authorization, provider credential을 넣지 않는다.
- Confluence write는 최신 version에 한 번만 수행하고 409를 포함한 실패를 자동 재시도하지 않는다.
- Confluence 실패는 활성화된 Edge/store를 되돌리지 않고 clipboard 전달을 막아 동일 command로 재개한다.
- active config에 같은 `principal_ref` 또는 `token_ref`가 있으면 새 raw token을 발급하지 않는다.

## 수동 확인이 필요한 safe code

다음 code는 자동 반복하지 않고 운영 상태를 먼저 확인한다.

- `operation_not_supported_by_single_entry`
- `environment_not_supported`, `environment_profile_invalid`
- `existing_mapping_ambiguous`, `store_edge_mapping_mismatch`
- `confluence_create_would_remove_user`, `confluence_target_ambiguous`
- `confluence_managed_heading_invalid`
- `edge_listener_unexpected`, `edge_automatic_rollback_failed`

그 외 network/readiness 실패는 동일 입력으로 한 번 재실행할 수 있다. raw token 또는 실제 principal을 최종 보고에 포함하지 않는다.
