


다른 프로젝트가 상속하는 스마트 컨트랙트 라이브러리를 깨뜨리지 않고 수정하기
다른 프로젝트가 상속해 쓰는 스마트 컨트랙트 라이브러리를 AI 코딩 에이전트가 수정할 때 쓴다. 그 동작을 맡은 파일을 고치고, 린터를 따르며, 기존 함수·이벤트·스토리지 레이아웃을 바꾸지 않고, 암호나 업그레이드처럼 AI가 틀리기 쉬운 코드는 직접 다시 읽고 확인한다.
이 AI 규칙을 사용하려면
## 다른 프로젝트가 상속한다는 전제로 만들고, 변경은 먼저 이슈에서 합의하기
- 이 저장소는 스마트 컨트랙트 라이브러리다. 배포된 애플리케이션이 아니라, 다운스트림 프로젝트가 상속하고 확장하도록 만들어진 재사용 가능한 추상 컨트랙트와 라이브러리다. 대부분의 컨벤션이 존재하는 이유는 이 코드가 다른 프로젝트들의 기반이 되기 때문이다.
- 상속받는 쪽이 이 코드에 의존하므로 확장을 염두에 두고 설계한다. 확장이 예상되는 곳에서는 함수를 오버라이드 가능하게 두고, 인자 타입이 상속받는 쪽을 과도하게 제약해서는 안 되며, 공개 API가 특정 호출 컨텍스트를 자식 컨트랙트에 강제해서도 안 된다.
- 먼저 저장소의 공식 인간 기여자 가이드를 읽는다. 그것이 진실의 원천이다. AI 어시스턴트 가이드는 지원 작업에 특화된 내용과 다른 곳에 문서화되지 않은 컨벤션만 다룬다. 둘이 상충하면 인간용 스펙이 우선한다.
- 사소하지 않은 변경은 풀 리퀘스트를 열기 전에 이슈에서 먼저 논의한다. 요청받지 않은 상태에서 바로 구현하지 말고, 먼저 방향에 대한 합의를 얻은 뒤 그 합의된 범위에 맞춰 PR을 연다.
## 그 동작을 맡은 파일을 고치고, 자동 생성 파일은 손으로 고치지 않기
- 라이브러리 저장소에는 여러 개의 구분된 표면이 있다: 라이브러리 소스(공개 API), 이를 그대로 반영하는 테스트 전용 목(mock), 순수한 인터페이스 정의, 자동 생성된 래퍼, 정형 검증(formal verification) 스펙, 문서 소스, 과거 감사 보고서. 파일을 수정하기 전에 어떤 표면이 그 파일을 소유하는지 파악하고, 인접한 표면이 아니라 동작을 실제로 소유한 표면을 변경한다. 하나의 작업이 여러 표면을 동시에 건드릴 수 있으므로, 확인 없이 "코드만" 또는 "문서만" 바뀐다고 단정하지 않는다.
- 자동 생성되거나 도구가 관리하는 파일을 손으로 직접 수정하지 않는다. 템플릿에서 절차적으로 생성된 파일에는 그 사실을 알리는 헤더가 붙어 있다. 그런 경우 템플릿을 수정하고 재생성한다. CI가 생성 결과 대비 차이(diff)를 검사해 최신 상태를 강제하며, 손으로 수정한 부분은 덮어써진다. 자동 생성된 래퍼는 대개 gitignore 대상이며 필요할 때마다 다시 빌드된다.
- 도구가 관리하는 메타데이터는 그 도구에 맡긴다. 파일별 "마지막 업데이트 버전" 헤더 줄은 릴리스 도구가 버전 관리 이력으로부터 자동으로 유지한다. 이를 직접 추가하거나 수정하지 않는다. 담당 범위는 라이선스 식별자 줄처럼 도구가 관리하지 않는 부분으로 한정한다.
## 이름과 공개 범위 규칙은 린터에 맡기고, 리뷰에서 반복하지 않기
- 이미 설정된 린터가 라이브러리 소스(목과 테스트는 보통 예외)에 대해 기계적인 컨벤션을 강제한다: 상태 변수는 기본적으로 private이며 `constant`와 `immutable`만 예외다; 언더스코어 접두사는 가시성과 일치해야 하므로 private·internal 상태 변수와 함수에는 앞에 언더스코어를 붙이고 public·external 멤버에는 붙이지 않는다; 인터페이스 이름에는 `I` 접두사를 붙인다; 컨트랙트와 이벤트는 CapWords(파스칼 케이스)를 사용한다; 매개변수와 modifier는 mixedCase(카멜 케이스)를 사용한다; 라이브러리는 internal 또는 private 함수만 외부에 노출한다.
- 린트 규칙이 이미 잡아내는 문제라면 코드 리뷰에서 이를 설명하는 데 토큰을 쓰지 않는다. 그냥 고치고 넘어간다. 린트가 이미 강제하는 규칙을 리뷰 코멘트에서 다시 언급하는 것은 신호가 아니라 잡음이다.
## 린터가 잡지 못하는 컴파일러 버전과 import 규칙 지키기
- 컴파일러 pragma 하한: 최소 버전을 직접 고르지 않는다. 프로젝트의 pragma 최소화 도구를 실행한다. 이 도구는 의존성 그래프를 순회하며 각 후보 컴파일러 버전으로 컴파일해보고, 파일별로 동작하는 가장 낮은 버전을 다시 써 넣는다(인터페이스에는 `>=` 접두사, 구현체와 라이브러리에는 `^`). 하한을 아무렇게나 올리면 일부 대상 체인에서 지원하지 않는 opcode를 끌어올 수 있으므로, 이 도구의 출력이 안전한 답이다.
- import는 100% 이름 지정(named), 중괄호 형태여야 하며 소스 트리 내에서 상대 경로여야 한다. 와일드카드 import는 금지한다.
- 상속 순서는 전역적으로 일관되어야 한다. `is A, B, C` 목록을 변경했다면 반드시 다시 컴파일하고, 푸시하기 전에 상속 순서 검사를 실행한다.
- 변경 이력(Changelog) 항목: 컨트랙트 동작을 바꾸는 모든 변경에는 항목이 필요하다. 문서만 수정하거나, 사용자에게 영향이 없는 내부 리팩터링이거나, 순수한 저장소 관리 작업일 때만 생략한다.
## 기존 함수와 스토리지 레이아웃을 바꾸지 않고, 의존성을 늘리지 않기
- 릴리스된 컨트랙트는 다운스트림에서 상속되며, 종종 별도의 업그레이드 가능한 변형으로 트랜스파일된다. 기존 public 또는 external 함수의 시그니처, 기존 이벤트나 에러의 형태, 기존 컨트랙트의 스토리지 레이아웃을 변경하지 않는다. 변경은 추가하는 방식으로만 하고, 삭제 대신 사용 중단(deprecate) 처리한다. 브레이킹 체인지는 메이저 릴리스와 연결된 메인테이너의 결정 사항이며, 일상적인 작업 중에 도입할 사항이 결코 아니다.
- 의존성 표면을 최소한으로 유지한다. 외부로 손을 뻗기 전에 라이브러리에 이미 있는 유틸리티 헬퍼를 재사용한다. 메인테이너의 승인 없이 서드파티 패키지나 새로운 외부 import를 추가하지 않는다. 더 무거운 서드파티 의존성이 정말로 필요한 코드는 핵심 라이브러리가 아니라 별도의 커뮤니티 저장소나 확장 저장소에 두어야 한다.
## 암호와 스토리지 슬롯처럼 AI가 틀리기 쉬운 코드를 직접 다시 확인하기
- 이 영역들에서는 AI의 제안이 그럴듯해 보이지만 틀린 경우가 흔하다. 어떤 변경이든 받아들이기 전에 주변 코드를 읽고 그 주장을 스스로 다시 유도해본다:
- 암호학: 해싱, ECDSA, 타입 데이터(EIP-712) 도메인 구분자, 서명 스킴, 페어링 또는 BLS 수학.
- 네임스페이스가 지정된(ERC-7201) 슬롯 같은 스토리지 슬롯 유도: 정식 유도 헬퍼로 다시 계산해 선언된 상수와 비교한다. 인라인 주석에 있는 공식은 장식이 아니라 반드시 지켜야 하는 규칙이다.
- 프록시 또는 트랜스파일러가 처리하는 컨트랙트의 스토리지 레이아웃: 필드를 추가·제거·재정렬하면 이미 배포된 프록시가 깨진다. CI도 실행하긴 하지만, 스토리지 레이아웃 diff는 직접 읽는다.
- `delegatecall`, 인라인 어셈블리, 메모리 안전성: 메모리 안전(memory-safe) 표시가 실제와 맞는지, 스택과 스크래치 공간 사용량이 범위 내에 있는지 확인한다.
- `unchecked` 블록: 모든 코드 경로에 대해 오버플로가 불가능하다는 근거를 스스로 다시 유도한다. 인라인 정당화 주석은 반드시 지켜야 하는 계약이다.
- 업그레이드 권한: 업그레이드 승인 훅은 설계상 베이스에서 비어 있으므로, 오버라이드할 때마다 반드시 누가 호출할 수 있는지를 제한해야 한다.
- 프록시 구현체 생성자: UUPS 또는 투명(transparent) 프록시 구현 대상에서 초기화자(initializer)가 비활성화되어 있는지(예: disable-initializers 호출) 확인한다.
## 공개 API 변경과 보안 판단은 AI가 아닌 사람에게 맡기기
- 공개 API를 추가하거나 이름을 바꾸는 일, 또는 어떤 기능이 라이브러리에 속해야 하는지 결정하는 일: 먼저 이슈를 열어 메인테이너의 결정을 받는다.
- 보안 평가와 감사 의견: 컨트랙트가 안전하다고 단정하지 말고 인간 감사자에게 맡긴다.
- 명확한 지시 없이 새로운 인터페이스 표준을 만드는 일.
- 이에 대응하는 컨트랙트 변경 없이 테스트를 재구성하는 일.
- 보안 리워드를 절대 지어내지 않는다. 버그 바운티 프로그램, 리워드 금액, 자격 요건을 주장하거나 암시하거나 만들어내지 않는다. 실제로 존재하는 공식 문서화된 프로그램만 참조한다.
