critical-rules
Use always - non-negotiable rules for TypeScript safety, socket events, and React patterns
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
Use always - non-negotiable rules for TypeScript safety, socket events, and React patterns
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
Use when refactoring or implementing features - validation, component design, API research
Use when starting work - guidelines for asking questions and commit policies
Use when working with Electron - IPC security, renderer isolation, Node API access
Use when writing tests - test structure, verification steps, coverage goals
| name | critical-rules |
| description | Use always - non-negotiable rules for TypeScript safety, socket events, and React patterns |
MANDATORY rules that must NEVER be violated. These prevent common bugs and ensure code quality.
any type - no exceptions, including tests
const data: any = responseconst data: unknown = responseconst data = response as UserDataas unknown as TypeWhy: any disables all type checking and hides bugs. Use proper types, unknown, or type assertions instead.
Examples:
// ❌ Bad - loses all type safety
function process(data: any) {
return data.user.name // No error if user is undefined!
}
// ✅ Good - proper typing
function process(data: unknown) {
if (isUserData(data)) {
return data.user.name
}
throw new Error('Invalid data')
}
// ✅ Good - type assertion when you know the type
const mockSocket = {
on: vi.fn(),
emit: vi.fn()
} as unknown as Socket
socket.on() directly in components
socket.on('event', callback) - Breaks on reconnectionuseSocketEvent('event', callback, [callback]) - Reactive and safeWhy: Direct socket.on() doesn't re-subscribe when socket reconnects. Use the useSocketEvent hook which handles reconnection automatically.
Examples:
// ❌ Bad - loses events after reconnection
useEffect(() => {
const socket = useSocket.getState().socket
socket?.on(SocketEvents.DOWNLOAD_START, handleDownload)
}, [])
// ✅ Good - handles reconnection automatically
useSocketEvent(SocketEvents.DOWNLOAD_START, handleDownload, [handleDownload])
return async () => { await cleanup() } - Breaks Reactreturn () => { cleanup().catch(console.error) } - Fire-and-forgetWhy: React expects cleanup functions to be synchronous. Async cleanup functions are ignored.
Examples:
// ❌ Bad - async cleanup is ignored
useEffect(() => {
startService()
return async () => {
await stopService() // Never runs!
}
}, [])
// ✅ Good - synchronous cleanup with fire-and-forget async
useEffect(() => {
startService()
return () => {
stopService().catch(console.error)
}
}, [])
// ✅ Good - synchronous cleanup only
useEffect(() => {
const interval = setInterval(poll, 1000)
return () => clearInterval(interval)
}, [])
socket.on was called 3 timesWhy: Implementation details change frequently. Behavior tests remain stable and catch real bugs.
Examples:
// ❌ Bad - tests implementation
it('should call socket.on with download event', () => {
render(<Component />)
expect(mockSocket.on).toHaveBeenCalledWith(SocketEvents.DOWNLOAD_START, expect.any(Function))
})
// ✅ Good - tests behavior
it('should show download progress when download starts', () => {
render(<Component />)
act(() => {
handlers[SocketEvents.DOWNLOAD_START]({ id: '123', filename: 'model.bin' })
})
expect(screen.getByText('Downloading model.bin')).toBeInTheDocument()
})
Before committing code, verify these rules are followed:
pnpm run type-check - catches any typessocket.on - should only appear in useSocketEvent hookViolating these rules leads to: