검색/멀티 모듈 저장소에 프로바이더와 제너레이터 플러그인 추가하기

멀티 모듈 저장소에 프로바이더와 제너레이터 플러그인 추가하기

시크릿용 프로바이더와 제너레이터로 확장되는 멀티 모듈 저장소에서 AI에게 작업을 맡길 때 사용하세요. 모든 작업을 태스크 러너로 실행하고, 정해진 방식으로 확장을 추가하며, 푸시나 릴리스 직전에 멈춥니다.

이 AI 규칙을 사용하려면
## 빌드와 테스트는 프로젝트 태스크 러너로만 실행하기 이 저장소는 빌드, 테스트, 린트, 패키징 명령을 하나의 태스크 러너를 통해 노출한다. 먼저 그 파일을 읽어 사용 가능한 타깃을 파악하고, 모든 작업을 그 타깃을 통해 호출한다. 기반이 되는 언어의 테스트 러너나 린터, 차트 도구를 직접 호출하지 않는다. 타깃은 빌드 태그, 모듈 범위, 환경, 생성 단계를 설정하는데, 직접 호출하면 이것들이 조용히 건너뛰어진다. 직접 호출하면 리뷰 게이트가 내놓는 결과와 일치하지 않는 초록불(통과) 결과가 나올 수 있다. ## 전체 리뷰 타깃을 돌리고 마지막에 생성물 차이 확인하기 변경에 대한 게이트는 그 안에 들어 있는 개별 검사가 아니라 단 하나의 통합 리뷰 타깃이다. 자신이 관련 있다고 생각하는 검사만 골라 실행하지 말고 통합 타깃을 실행한다. 모든 것을 커밋한 뒤, 마지막 단계로 생성물 diff 검사를 실행한다. 상당한 양의 생성 콘텐츠가 메인 리뷰 타깃 바깥에 존재한다. 패키징 차트 테스트, 렌더링된 매니페스트, 문서가 그렇다. 그 검사 이후 워킹 트리가 깨끗하다는 것이 그 모두가 재생성되었다는 증거다. 이 단계는 불필요하게 느껴진다는 바로 그 이유 때문에, 에이전트가 작성한 변경이 무너지는 가장 흔한 지점이다. ## 생성된 파일은 손대지 말고 원본 타입이나 템플릿 고치기 생성물로 표시된 파일은 기여자가 아니라 그 생성기가 소유한다. 문자 하나를 고치는 경우라도 절대 손으로 편집하지 않는다. 그 파일이 만들어지는 원본 타입이나 템플릿을 바꾼 뒤, 생성 타깃을 실행한다. 이 타깃은 통합 리뷰 타깃에 이미 포함되어 있다. 손으로 편집한 내용은 다음 재생성 시점까지만 살아남고, 그 다음에는 경고 없이 사라지거나 다른 사람이 풀어내야 하는 혼란스러운 diff를 만든다. ## 매니페스트는 차트에서, 스냅샷은 업데이트 타깃으로 다시 생성하기 패키징 차트가 배포 매니페스트의 단일 진실 공급원이다. 저장소에 커밋된 정적 매니페스트는 그 차트에서 생성되므로, 출력물을 편집하지 말고 차트를 편집한 뒤 재생성한다. 스키마 테스트는 스냅샷 테스트를 사용한다. 스키마 타입을 변경한 뒤에는 스냅샷 파일을 직접 편집하지 말고 스냅샷 갱신 타깃을 실행한 다음 그 결과 diff를 검토한다. 예상치 못한 스냅샷 변경은 받아들여도 되는 잡음이 아니라, 자신의 타입 변경을 다시 읽어보라는 신호로 취급한다. ## 설계 결정과 비교한 대안을 커밋 노트에 쓰기 사소하지 않은 모든 커밋에는, 핵심 설계 결정과 저울질한 트레이드오프, 부딪힌 함정을 기술한 커밋 노트를 붙인다. 노트는 커밋에 계속 붙어 있고 이후에도 조회할 수 있어서, diff만으로는 담을 수 없는 사고 과정을 보존한다. 노트는 사실에 근거해 구체적으로 쓴다. 무엇을 선택했고, 무엇을 버렸으며, 왜 그랬는지를 쓴다. diff를 그대로 되풀이하기만 하는 노트는 낭비다. ## 알아차리기 어려운 패턴을 머지 전에 공유 가이드에 추가하기 구현 중에 자명하지 않은 패턴을 발견하면, 맥락이 사라진 나중이 아니라 그 변경이 병합되기 전에 공유 가이드 문서에 추가한다. 항목은 마침 자신이 만들고 있던 단일 기능이 아니라 코드베이스 전반에 적용될 만큼 일반적으로 유지한다. 확장 하나만 설명하는 패턴이라면 그 확장 자체의 문서에 들어가야 한다. ## 확장마다 모듈을 따로 두고 빌드 태그는 등록 파일에 두기 선택적 확장은 자신의 이름을 딴 디렉터리 아래 자체 모듈에 존재하며, 확장 패키지 자체는 빌드 태그를 갖지 않는다. 빌드 태그는 그 확장을 위한 중앙 등록 파일에 속한다. 이렇게 분리하면 확장 패키지는 단독으로 컴파일과 테스트가 가능한 상태로 유지되고, 어떤 확장을 링크할지는 배포되는 바이너리가 결정한다. 모듈 대체(replace) 항목은 루트 모듈 파일에 알파벳 순으로 추가한다. 빌드는 선택된 확장 집합을 빌드 태그로 전달하며, 기본값은 모든 확장을 의미한다. ## 확장의 설정 타입을 공유 유니온 타입에 한 줄로 등록하기 새 확장의 설정 타입은 공유 API 패키지 안의 자체 파일에 넣는다. 등록은 판별자 유니온 구조체에 한 줄짜리 슬롯을 추가해서 하며, 그 필드의 직렬화 태그가 곧 확장 이름이다. 해석은 마샬링된 유니온의 첫 번째 키를 기준으로 동작하므로, 그 태그는 정확하고 고유해야 한다. 인증은 전용 auth 구조체 아래에 중첩한다. 여러 인증 방식을 제공할 때는, 모호한 설정이 런타임이 아니라 어드미션 시점에 거부되도록 그 구조체를 최대 한 개의 속성만 갖도록 제약한다. 백엔드가 TLS로 통신하는 경우에는 언제나 인증서 번들 필드와 인증서 프로바이더 필드를 포함한다. 동결된 API 버전이라도 완전히 새로운 확장 슬롯은 여전히 받아들인다. 닫혀 있는 것은 기존 필드 쪽이다. ## 자격 증명은 공유 헬퍼로 읽고 네임스페이스를 넘지 않기 자격 증명 해석, 인증서 가져오기, 셀렉터 검증, 메타데이터 파싱, 메트릭 라벨 상수는 모두 공유 헬퍼가 있다. 그것들을 사용하고, 스토어 kind와 소비하는 리소스의 네임스페이스를 각 헬퍼가 기대하는 그대로 정확히 전달한다. 특히 자격 증명 리졸버는 클러스터 범위 스토어와 네임스페이스 범위 스토어를 구분하는 네임스페이스 스코핑 규칙을 강제한다. 직접 만든 조회는 소리 없이 네임스페이스를 넘나드는 시크릿 읽기가 되며, 이는 스타일 문제가 아니라 권한 상승이다. 스토어가 없는 확장 kind는 빈 스토어 kind를 전달한다. 그런 확장에는 네임스페이스 스코핑이 적용되지 않기 때문이다. ## 클라이언트의 모든 메서드를 구현하고 지원하지 않는 작업에는 전용 오류 반환하기 클라이언트 인터페이스는 전부 필수이며, 오직 close 메서드만 아무 일도 하지 않는 no-op이어도 된다. 시크릿이 없을 때는 전용 not-found 센티널 에러를 반환한다. 리콘실러의 삭제 정책이 "없음"과 "실패"를 구분하는 데 의존하기 때문이다. 기능(capability)은 읽기 전용, 쓰기 전용, 읽기 쓰기 중 무엇인지 정직하게 선언한다. 읽기 전용 구현도 write와 delete 메서드를 여전히 구현하되, 그 메서드에서는 반드시 센티널 에러를 반환해야 하며 nil 에러를 반환해서는 절대 안 된다. nil 에러는 실제로 일어나지도 않은 동작을 조용히 성공했다고 보고하게 된다. JSON 페이로드 내부의 속성 조회에는 관례적인 JSON 경로 추출기를 사용한다. ## 클라이언트 생성이 느리거나 비쌀 때만 캐시 추가하기 기본은 캐시 없음이다. 토큰 교환, 리스 획득, 아이덴티티 페더레이션처럼 클라이언트 생성 비용이 정말로 클 때만 캐시를 추가한다. 클라이언트 단위 캐시는 스토어의 이름, 네임스페이스, kind를 키로 삼고, 설정 편집이 자동으로 항목을 무효화하도록 스토어 오브젝트의 리소스 버전으로 버전을 매겨야 한다. 시크릿 단위 캐시는 만료 기능이 있고 크기가 제한된 캐시로 클라이언트 내부에 두어야 하며, 그 수명과 최대 크기는 하드코딩된 상수가 아니라 사용자에게 노출되는 설정이어야 한다. ## 기능 플래그를 차트 값부터 초기화까지 연결하기 기능 플래그는 정해진 경로를 지난다. 패키징 차트 값, 그다음 디플로이먼트의 추가 인자, 그다음 커맨드라인 플래그, 그다음 플래그 등록, 그다음 초기화 순서다. 플래그는 확장 패키지의 이니셜라이저에서 등록하고, 루트 커맨드가 그것들을 모으게 하며, 초기화는 등록 도중이 아니라 매니저가 시작된 뒤에 실행한다. 프로세스 밖에서 실행되는 의존성은 메인 바이너리에 링크하지 말고 사이드카 서브차트로 배포한다. 어떤 부류의 확장에 기능 플래그의 선례가 없다면 기존 패턴을 따르되, 자신이 첫 사례가 될 것을 예상하고 리뷰에서 그 사실을 밝힌다. ## 스캐폴드 명령으로 시작하고 빠진 부분 채우기 새 확장을 위한 부트스트랩 명령이 있다면 먼저 그것을 실행하고, 문서화된 수동 단계를 그것이 만들어낸 것과 빠뜨린 것을 확인하는 점검 목록으로 취급한다. 스캐폴드는 대개 API 타입, 모듈 파일, 등록 호출, 판별자 유니온 항목, kind 열거값, 리졸버 스위치를 배선한다. 반면 접근 제어 규칙, 문서 페이지, 예제 스니펫, 내비게이션 항목, 패키징은 대개 배선하지 않는다. 스캐폴드가 일을 끝냈다고 가정하지 말고, 다뤄지지 않은 목록을 하나씩 명시적으로 훑는다. ## 제너레이터는 상태 없이 두고 정리 작업은 두 번 실행돼도 안전하게 만들기 제너레이터 계열 확장은 설정을 원시 JSON 블롭으로 받아 스스로 언마샬하고, 생성된 값들을 키 단위가 아니라 한 번의 호출로 전체 맵으로 반환하며, 생성과 정리 사이에 영속화되는 불투명한 상태 블롭을 반환한다. 기본은 무상태로 둔다. 상태를 반환하지 않고 정리도 no-op으로 한다. 상태는 외부 리소스를 나중에 해제해야 할 때만 반환한다. 정리는 반드시 멱등이어야 한다. 프레임워크가 생성 후 상태 영속화에 실패했을 때 롤백으로 그것을 호출하고, 삭제 시에는 파이널라이저를 통해 다시 호출하기 때문이다. ## 중앙 등록 파일에서 확장을 등록하고 이름 중복 피하기 확장 패키지는 작고 고정된 생성자 및 메타데이터 심볼 집합을 익스포트하며, 등록은 그 심볼들을 레지스트리에 넘기는 중앙 파일에서 이루어진다. 등록은 이름이 중복되면 패닉을 일으키므로, 식별자를 신중하게 고르고 아직 사용되지 않았는지 확인한다. 스킴 등록은 동작 등록과 별개이며 둘 다 필요하다. 런타임 리졸버는 스킴을 통해 타입이 지정된 오브젝트를 로드한 다음, kind에 따라 등록된 구현으로 디스패치한다. 클러스터 범위의 우산 타입이 유니온 스펙으로부터 합성된 네임스페이스 오브젝트를 만들어내는 경우, 모든 확장은 그 변환에 자신의 case를 가지고 있어야 한다. ## 확장마다 문서 페이지를 쓰고 공유 스니펫 재사용하기 확장에 대한 문서 페이지를, 관례적인 섹션 순서에 따라 작성한다. 소개, 인증 또는 설정, 소비하는 리소스의 스펙, 그리고 선택적인 푸시 또는 쓰기 흐름 순이다. 실행 가능한 예제는 공유 스니펫 디렉터리에 두고 텍스트를 복제하는 대신 페이지에 트랜스클루드해서, 한 번의 수정이 모든 곳에 전파되도록 한다. 공유 인증 방식은 독립된 페이지에 한 번만 문서화하고, 각 서비스별 페이지에 복사하는 대신 그 페이지로 링크한다. 내비게이션 항목은 해당 섹션의 맨 아래에 덧붙인다. 순서가 알파벳순이 아니라 역사적 순서이기 때문이다. ## 로컬에서만 작업하고 푸시나 릴리스는 하지 않기 에이전트는 저장소를 조사하고, 코드를 설명하고, 변경을 제안하고, 로컬 파일을 편집하고, 테스트를 작성하고, 문서를 갱신하고, 검사를 실행하고, 사람이 리뷰할 로컬 diff를 준비할 수 있다. 에이전트는 풀 리퀘스트 생성, 브랜치 푸시, 릴리스 배포, 패키지 업로드, 저장소 설정 변경, 권한 변경, 자격 증명 교체, 시크릿 수정, 그 밖의 어떠한 외부 쓰기 행위도 해서는 안 된다. 차단된 행동을 요청받으면 그것을 수행하지 않는다. 대신 요청받은 행동, 그것이 차단된 이유, 완료한 로컬 작업이 있다면 그 내용, 그리고 사람 기여자가 다음에 밟아야 할 수동 단계를 기록한 로컬 파일을 만든다. ## 완료라고 하기 전에 최소한의 차이와 테스트 실행 확인하기 작업을 완료로 제시하기 전에 다음을 검증한다. 의도가 문서화되어 있는지, diff가 최소하고 외과 수술적이며 그 작업과 무관한 인접 주석이나 코드를 건드리지 않는지, 관련 테스트를 프로젝트 태스크 러너를 통해 실행했는지, 그리고 문서를 갱신했는지. 검증의 어느 부분이라도 완료하지 못했다면, 부분적으로만 검증된 변경을 끝난 것처럼 제시하지 말고 그 사실을 명시하고 이유를 설명한다.