효과적인 검사 작성
좋은 검사는 새 팀원이 코드를 읽고 적용할 수 있는 규칙처럼 읽힙니다. 파일 형식과 옵션은 저장소 검사를 참고하세요.
검사당 판단 가능한 규칙 하나
서로 관련 없는 규칙은 각각 별도 파일에 두세요. 발견 사항에는 검사 파일 이름이 라벨로 붙으며, 각 파일은 자체 패턴을 가집니다.
규칙을 코드에 대한 조건으로 작성하세요. 무엇이 규칙을 어기고 무엇이 충족하는지 적습니다.
파일 패턴으로 범위 지정하기
규칙이 중요한 곳에만 검사가 적용되도록 files 패턴을 추가하세요. 패턴이 없으면 모든 풀 리퀘스트에 적용됩니다. 테스트나 픽스처는 !로 제외하고, YAML에서는 모든 패턴을 따옴표로 감싸세요.
이유와 예시 제시하기
규칙이 왜 중요한지 적어 두면 HeyDeer가 예상하지 못한 경우도 판단할 수 있습니다. 규칙을 어기는 코드뿐 아니라 올바른 코드도 설명하고, 코드베이스에서 가져온 짧은 잘못된 예시와 올바른 예시를 함께 넣으세요.
검사를 짧고 순서 있게 유지하기
대부분의 좋은 검사는 한 화면에 들어갑니다. 여러 검사에 같은 배경 지식이 필요하다면 스킬로 옮기세요.
각 검토는 일치하는 검사를 파일 이름 순서로 최대 10개까지 적용하므로, 가장 중요한 검사 앞에 10-auth.md처럼 숫자를 붙이세요. 단순한 검사에는 skip_extra_reviewers: true를 설정하면 심층 검토에서도 표준처럼 검토합니다. 검토당 최대 10개 검사를 참고하세요.
실제 풀 리퀘스트로 테스트하기
- 검사를 병합하세요. HeyDeer는 베이스 브랜치에서 검사를 읽습니다.
- 규칙을 어기는 풀 리퀘스트를 열어 발견 사항에 검사 이름이 표시되는지 확인하세요. 규칙을 따르는 코드에는 발견 사항이 없는지도 확인하세요.
- 검사가 올바른 코드를 지적하면 규칙이나 패턴을 더 엄격하게 하세요. 놓치는 경우가 있으면 그 경우를 잘못된 예시로 추가하세요.
안티패턴
| 안티패턴 | 실패하는 이유 | 대신 이렇게 작성 |
|---|---|---|
| 모호함: “API 설계 모범 사례를 따르세요.” | 코드를 판단할 조건이 없어 발견 사항이 들쭉날쭉합니다. | “src/api/ 아래의 핸들러는 라우트의 스키마로 요청 본문을 검증한다.” |
| HeyDeer가 볼 수 없음: “CI가 통과하고 보안 승인을 받지 않았다면 실패로 처리하세요.” | HeyDeer는 CI 결과나 승인 여부를 볼 수 없습니다. | 필수 CI와 승인에는 GitHub 브랜치 규칙을 사용하세요. |
| 실행 요구: “테스트를 실행하고 결과를 보고하세요.” | HeyDeer는 코드, 테스트, 빌드를 실행하지 않습니다. | “src/billing/의 변경에는 변경된 함수를 실행하는 테스트가 포함된다.” |
| 포매팅: “두 칸 들여쓰기를 사용하고 import를 정렬하세요.” | 포매터나 린터가 이를 정확하게 강제합니다. | 그런 도구는 CI에서 실행하세요. |
| 추측: “느릴 수 있는 부분을 모두 지적하세요.” | 구체적인 패턴이 없으면 발견 사항이 의견이 됩니다. | “루프에서 항목마다 데이터베이스 쿼리를 하나씩 실행하면 안 된다. 대신 쿼리를 일괄 처리한다.” |
| 한 파일에 여러 규칙: “인증, 로깅, 이름 규칙, 테스트를 확인하세요.” | 발견 사항이 하나의 라벨을 공유하고, 규칙별로 범위를 따로 지정할 수 없습니다. | 규칙마다 파일 하나, 각각 자체 패턴 포함. |
변경 전과 후
변경 전:
---
files: "src/**"
---
Follow API best practices. Make sure endpoints are secure, fast,
and well tested, and that naming is consistent. Run the test suite
and fail if anything breaks.변경 후(.agents/checks/20-api-workspace-scope.md):
---
files:
- "src/api/**/*.ts"
- "!**/*.test.ts"
---
# API handlers scope queries to the caller’s workspace
Every query in an API handler that reads or writes a table with a
`workspace_id` column must filter on the workspace returned by
`requireWorkspace()`. Without that filter, one customer can read
or change another customer’s data.
Fail when a handler queries such a table without that filter.
Pass when every such query filters on the workspace, or when the
handler only touches tables without a `workspace_id` column.
Incorrect:
```ts
const invoice = await db.query.invoices.findFirst({
where: eq(invoices.id, id),
});
```
Correct:
```ts
const { workspaceId } = await requireWorkspace(req);
const invoice = await db.query.invoices.findFirst({
where: and(eq(invoices.id, id), eq(invoices.workspaceId, workspaceId)),
});
```다시 작성한 검사는 한 가지 관심사만 다루고, API 핸들러로 범위를 한정하고, 무엇이 실패하고 무엇이 통과하는지 밝히며, 위험을 설명합니다. 나머지 관심사는 별도의 검사가 되거나 도구와 AGENTS.md로 옮겨집니다.