Installs into .claude/skills of the current project.
Sponsors
SSkills DirectorySkills Directory
Is that skill safe to install?
SSkills DirectorySkills Directory
Know which skills are safe — weekly.
Are you the author of Liveops?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/snwlee-liveops)
---
name: liveops
description: 라이브옵스 — 이벤트 캘린더·경제 싱크/소스·리텐션 가정·롤백 경로를 정합성으로 판정한다. 트리거 "라이브옵스", "이벤트 캘린더", "리텐션", "시즌", "운영 지표", "롤백".
---
# liveops
nereus:common 규칙을 따른다. 담당 에이전트: architect.
**엔진과 무관하다** — 로블록스든 Unity든 Switch든 계획의 정합성은 같은 기준으로 본다.
시뮬레이터·타이쿤과 오비는 **출시가 시작**인 장르다. 만드는 것까지만 덮는 하네스는
이 장르에서 절반만 쓸모 있다.
## 0. 지표는 주입구다 — 없다고 게이트가 꺼지지 않는다
실제 운영 지표(로블록스 Open Cloud Analytics 등)는 아직 연결돼 있지 않다.
그래도 **계획의 내적 정합성**은 지표 없이 판정할 수 있다.
| 검사 | 지표 필요 | 없을 때 |
|---|---|---|
| 이벤트 구간 겹침 | 아니오 | 그대로 판정 |
| 경제 싱크/소스 균형 | 아니오 | 그대로 판정 |
| 리텐션 곡선 형태 | 아니오 | 그대로 판정 |
| 롤백 경로 존재 | 아니오 | 그대로 판정 |
| 실측 리텐션 편차 | **예** | `unmeasured` 에 `retention-actual` 로 남는다 |
`Ruling: 미설정과 실패를 구분한다` 의 도메인 적용이다. 지표가 생기면 `metrics` 를 채우면 된다 —
검사기를 고치지 않는다.
## 1. 계획을 JSON 으로 적는다
```json
{
"events": [
{ "name": "halloween", "start": 1, "end": 5, "rollback": "이벤트 플래그 off + 보상 지급 중단" },
{ "name": "winter", "start": 6, "end": 9, "rollback": "이벤트 플래그 off" }
],
"economy": {
"sources": [{ "name": "quest", "amount": 100 }],
"sinks": [{ "name": "shop", "amount": 90 }]
},
"retention": { "d1": 0.4, "d7": 0.2, "d30": 0.1 }
}
```
구간은 **반열린 구간** `[start, end)` 다. 앞 이벤트의 `end` 와 뒤 이벤트의 `start` 가 같은 것은 겹침이 아니다.
## 2. 검사
```bash
echo '{"genre":"sim-tycoon","plan":{...}}' | node "${CLAUDE_PLUGIN_ROOT}/lib/liveops-plan.mjs"
```
실측 지표가 있으면 같은 JSON 에 `"metrics": { "retention": { "d1": 0.38, "d7": 0.19, "d30": 0.1 } }` 를 넣는다.
| 위반 코드 | 뜻 |
|---|---|
| `overlap` | 두 이벤트의 구간이 겹친다 |
| `no-rollback` | 그 이벤트에 롤백 경로 선언이 없다 |
| `no-sink` | 경제에 소스만 있고 싱크가 없다 — 인플레가 확정돼 있다 |
| `retention-shape` | 리텐션 가정이 뒤로 갈수록 올라간다 |
| `retention-drift` | 실측이 가정에서 장르 허용치보다 멀다 |
허용치는 장르 프로파일의 `liveops.retentionDriftPct` 에서 온다.
## 2-1. 원격 설정 — 라이브옵스에서 가장 위험한 코드
원격 설정은 **원격으로 바뀌고, 관찰이 어렵고, 틀리면 몇 주 동안 아무도 모른다.**
이벤트 캘린더보다 먼저 여기를 본다. 조종간이 잘못돼 있으면 계획이 맞아도 소용없다.
### ★ 최대 함정: 번들 기본값이 하위 폴백을 죽인다
> **번들 기본값이 있는 키는 원격에 값이 없어도 "설정됨"으로 판정된다.**
> 그래서 그 아래 폴백 계층(등급 내장 기본값 · 플레이버 로컬 설정 · 정책 상수)이
> 실행되지 않고 **조용히 죽는다.**
에러도 없고 로그도 없다. 기능이 안 보일 뿐이고, 안 보이는 것은 원래 그럴 수도 있어서
**몇 주 동안 수익이 새는 채로 돌아간다.** 실제로 이 사고로 **접이식 배너가 전 등급
영구 OFF** 가 된 이력이 있다(채굴 출처의 기록).
이 함정은 **키 이름만 보면 절대 안 보인다.** 검사로 잡지 못하면 사람은 못 잡는다.
### 키를 다섯으로 분류한다
| 분류 | 미설정이면 | 번들에 넣어도 되나 |
|---|---|---|
| 다크십 | 기능이 **존재하지 않는다** | **안 된다** — 발행 전에 켜진 채로 나간다 |
| 하위 계층이 결정 | 등급 표·플레이버·정책 상수가 정한다 | **안 된다** — 그 계층이 죽는다 |
| 안전 기본값 ON | 보호가 켜진다 | 된다 — 번들 값이 곧 보호값이다 |
| 등급·실험 전용 | 해당 없음(전역 해석 대상이 아니다) | **안 된다** — 타겟팅이 무너진다 |
| 하한 클램프 | 안전 하한으로 조인다 | 된다 — 번들 값이 하한 자체다 |
**분류 이름은 제품마다 다르다.** 보편적인 것은 이름이 아니라 구조다 —
각 분류는 `bundleSafe` 와 `why` 를 갖는다. `remote-config.json` 에 기본 체계가 있고
호출자가 덮어쓴다.
### 검사
```bash
echo '{"declared":[...],"classified":{"darkShipped":[...],...},"bundleDefaults":[...]}' \
| node "${CLAUDE_PLUGIN_ROOT}/lib/remote-config-check.mjs"
```
| 코드 | 심각도 | 뜻 |
|---|---|---|
| `bundle-unsafe` | **`incident`** | 하위 폴백을 죽이는 키가 번들에 있다. **사고 재현 가능** |
| `unclassified` | `trust` | 선언됐는데 분류가 없다. 어떤 폴백이 적용될지 아무도 모른다 |
| `phantom` | `trust` | 분류·번들에 있는데 선언에 없다. 영원히 기본값이다 |
| `multi-class` | `trust` | 한 키가 여러 분류에 있다. 어느 규칙이 이기는지 알 수 없다 |
| `key-pattern` | `trust` | 이름 규칙 위반. 키는 사람이 콘솔에서 손으로 친다 — 오타가 새 키를 만든다 |
**심각도를 나누는 이유**: 실제로 사고를 낸 것은 `bundle-unsafe` 하나다. 나머지 넷은
분류를 믿을 수 있게 만드는 **전제 조건**이다 — 분류가 비거나 겹치면 번들 안전 판정
자체가 의미를 잃는다. 같은 무게로 보고하면 진짜가 묻힌다.
`bundleDefaults` 를 안 주면 그 검사를 건너뛴다. **빈 배열(번들에 아무것도 없다)과
미제공(모른다)은 다른 상태다.**
### 검사기가 못 보는 것
- **값 해석**: `0` 은 무제한이 아니라 **하한으로 조여진다.** 쿨다운 키로 쿨다운을
**올릴 수는 없다**(하한만 조인다). 빈도 `0` 은 명시적 비활성으로 남고 양수는 최소 유효값으로
올라간다. 이것들은 구조가 아니라 값이라 여기서 안 잡힌다 — **코드에서 지킨다.**
- **등급·실험 혼용의 실제 사용처**: "등급 타겟팅은 `{base}_{segment}` 키, A/B 실험은
전역 기저 키 + 실험 그룹 라벨, **같은 키에 섞지 않는다**"는 규칙의 위반을
데이터만으로는 끝까지 못 본다. **못 보는 것은 못 본다고 적는다** —
검사기가 다 본다고 믿게 만드는 것이 더 나쁘다.
## 3. 롤백 경로는 선택이 아니다
라이브 게임에서 되돌릴 수 없는 이벤트는 사고다. 각 이벤트에 "무엇을 끄면 원상복구되는가"를
한 줄로 적는다. 적을 수 없다면 그 이벤트는 아직 설계가 끝나지 않은 것이다.