con un clic
safety-rules
상태 머신·보호 장치·Observer 룰. content.ts, observer.ts, background.ts 수정 시 참조.
Instalar con Codex o Claude Copia este prompt, pégalo en Codex, Claude u otro asistente, y deja que revise la página de la skill y la instale por ti.
Menú
상태 머신·보호 장치·Observer 룰. content.ts, observer.ts, background.ts 수정 시 참조.
Instalar con Codex o Claude Copia este prompt, pégalo en Codex, Claude u otro asistente, y deja que revise la página de la skill y la instale por ti.
Basado en la clasificación ocupacional SOC
YouTube 자막 번역 룰 (파이프라인, cue 병합, rolling 번역, 캐시). youtube/ 디렉토리 수정 시 참조.
페이지 번역 룰 (text detection, injection, batch, cache). text-detector.ts, translator.ts, constants.ts 수정 시 참조.
b3rys translate 크롬 확장을 GitHub에서 설치하고 API 키 설정·사용법까지 끝까지 안내한다. 사용자가 `/b3translate`을 실행하거나, repo URL을 붙여넣거나, "b3rys 번역 확장 설치/사용법"을 요청하면 사용.
선택 번역 팝업 룰 (단어/문장 모드, UI, 캐시). selection-popup.ts, llm-helpers.ts 수정 시 참조.
| name | safety-rules |
| description | 상태 머신·보호 장치·Observer 룰. content.ts, observer.ts, background.ts 수정 시 참조. |
removeAllTranslations() 호출 금지 → BLOCK_ID 전부 제거 → 전체 재감지 → 무한 루프. observer발 재시작(pendingRestart) 경로도 동일 — 전체 제거 없이 증분 재시작만translatePage 시작부의 purgeAllTranslations()는 HIDING_CLASS 있을 때만 (토글 OFF 잔재 정리 전용). 무조건 purge하면 살아있는 번역+BLOCK_ID가 매 패스마다 전부 뜯겨 "증분"이 전체 재주입으로 변질 → 화면 출렁임 + breaker 오카운트 (실제 있었던 버그)recentStarts 배열 리셋 금지 → circuit breaker 무력화myGen !== startGen 체크 누락 금지 → stale 결과가 상태 오염clearTimeout(errorTimeout) 누락 금지 → 이전 타이머가 loading 상태 덮어씀forceReplace 경로에서 물리 교체 금지 → markOriginalContent() + CSS 토글만 사용 (물리 교체 시 모드 전환 불가)상태: idle | loading | done | error
| 현재 | 이벤트 | 다음 | 조건 |
|---|---|---|---|
| idle | FAB 클릭 | loading | API 키 존재 |
| idle | autoTranslate | loading | translationEnabled=true |
| loading | 번역 완료 | done | myGen === startGen일 때만 |
| loading | FAB 클릭 (취소) | idle/done | cancelTranslation() + cleanupLoaders(), hasTranslationsOnPage에 따라 |
| loading | Observer added | loading | 취소 금지 — pendingRestart만 세팅, 완료 후 증분 (Gmail 등 SPA churn이 in-flight 배치·주입된 번역을 버리는 것 방지) |
| loading | Observer replaced | loading | pendingRestart + cancelTranslation() — 진짜 페이지 전환, 완료 후 전체 재시작 |
| loading | API 에러 | error | |
| done | FAB 클릭 | idle | removeAllTranslations() 실행 |
| done | Observer 새 콘텐츠 | loading | 증분 번역 (BLOCK_ID 보존, removeAll 금지) |
| error | 3초 타이머 | idle/done | circuit breaker 에러가 아닌 경우만, state==='error' 가드 |
| error | FAB 클릭 | loading | recentStarts.length=0 리셋 (FAB 클릭만 허용) |
| # | 이름 | 위치 | 임계치 | 발동 시 동작 |
|---|---|---|---|---|
| 1 | Circuit Breaker | translation-state.ts | 30회 시작/분 | state='error' + translationEnabled=false + FAB 클릭으로만 리셋. 생산적 패스만 카운트 — translatePage가 'empty'(새 블록 0개) 반환 시 recentStarts.push 생략. 동적 페이지(Gmail churn)에서 번역할 게 없는데 터지는 것 방지. push는 translatePage 완료 후 결과 기준으로 실행 |
| 2 | Rate Limiter | background.ts | 150 API콜/분 | 에러 응답 반환, 1분 후 자동 해제. 캐시 hit 제외. content와 완전 독립. 전역(모든 탭+YouTube rolling 공유)이라 정상 대량 사용 위로 설정 |
| 3 | startGen | content.ts | generation counter | myGen !== startGen → 상태 변경 없이 return |
| 4 | translateGen | translator.ts | generation counter | cancelTranslation() → translateGen++ → 이전 배치 DOM 주입 차단 |
| 5 | errorTimeout | content.ts | 3초 타이머 가드 | startTranslation() 시 clearTimeout + 콜백 내 state!=='error' 가드 |
| 6 | isB3rysElement | observer.ts | 패턴 매칭 | data-b3rys-_ 속성 또는 b3rys-_ 클래스 → 무시 (자체 DOM 변경 필터) |
| 7 | Fight Guard | fight-guard.ts | 같은 텍스트 3회 주입/90초 | 앱(Gmail 등)이 자기 DOM을 재렌더해 번역을 되돌리는 "소유권 싸움" 감지 → 해당 블록 세션 동안 양보(재번역 중단). 감지는 텍스트 키 기반(요소는 재렌더마다 죽음) |
Observer는 변경의 종류를 판정해 전달한다 (ContentChangeKind):
added — 콘텐츠 추가만, 감지된 블록(BLOCK_ID) 무손실replaced — 감지된 블록이 제거됨 = 진짜 콘텐츠 교체/SPA 전환 (한 debounce 창에서 replaced가 added에 우선)상태머신 정책:
state === 'done' → startTranslation() (증분, BLOCK_ID 보존)state === 'loading' + added → pendingRestart만 (취소 금지 — in-flight 배치 보존, 완료 후 증분)state === 'loading' + replaced → pendingRestart = true + cancelTranslation()withScrollCompensation(scroller, mutate)로 감싼다 — 무보정 변이가 viewport 위에서 일어나면 스크롤 움찔거림의 직접 원인getScrollContainer()로 도출 — Gmail처럼 내부 div가 스크롤하는 앱 대응. window.scrollBy 직접 호출 금지findContentAnchor(scroller) — 스크롤러 rect 내부 좌표를 여러 깊이(60/140/240/360px)로 탐침하고 scroller.contains(el) 검증. ⚠️ 창 좌표 (중앙, y=100) 고정 탐침 금지 — Gmail의 fixed 툴바에 얹혀 drift가 항상 0으로 측정되어 보정이 죽는다 (실제 있었던 버그)BUILD_TAG 로그 — 리빌드 후 확장 리로드+페이지 새로고침 안 된 stale 번들 판별용myGen === startGen인가? (아니면 stale 결과 → return)clearTimeout(errorTimeout) 했는가? (새 번역 시작 시)recentStarts.length < CIRCUIT_MAX인가? (걸렸으면 번역 불가)translationEnabled 값이 circuit breaker에 의해 false가 아닌가?새 보호 장치 추가:
| # | 할 일 |
|---|---|
| 1 | 기존 보호 장치(generation counter, circuit breaker 등)와 충돌 확인 |
| 2 | DOM 변경 시 isB3rysElement() 필터 통과 여부 확인 (Observer 루프 방지) |
| 3 | 수동 복구 경로 존재 확인 (FAB 클릭으로 리셋 가능해야 함) |
| 4 | 이 스킬 파일의 보호 장치 테이블에 행 추가 |
| 5 | docs/safety.md에 다이어그램/시나리오 추가 (사람용) |
상태 전이 변경:
| # | 할 일 |
|---|---|
| 1 | 이 스킬 파일의 상태 전이 테이블 업데이트 |
| 2 | docs/safety.md의 상태 전이도 업데이트 (사람용) |