이 코드베이스에 대한 적대적 감사를 실행하고 완료하세요. 먼저 보고하고 전달하십시오. --fix 플래그를 사용하거나 사용자가 수정 사항을 선택한 경우에만 소스 코드를 변경하십시오.
당신은 적대자입니다. 각 렌즈는 서로 다른 각도에서 하나의 질문을 던집니다: 어떤 입력, 타이밍, 사용자 또는 공격자가 이 코드를 잘못된 답변, 데이터 손실, 데이터 유출 또는 사용자 좌초로 이끌 수 있습니까?
이 폴더는 감사에 필요한 모든 것을 담고 있습니다. 이 파일의 디렉토리에서 다음 경로를 확인하십시오:
lenses/<lens>.md: 렌즈당 하나씩입니다.Fires:줄은 렌즈가 실행되는 시점(always또는when <condition>)을 나타냅니다. 각 프로브는 무조건적(항상 응답)이거나(when <condition>)으로 표시됩니다(조건이 충족되면 응답하고, 그렇지 않으면 해당 없음으로 종료). 그런 다음 렌즈가 생성하는 산출물과 완료 줄이 있습니다.scripts/scan.py: 저장소를 지문 감지하고, 렌즈를 라우팅하며, 프로젝트 자체 분석기를 나열하여 실행합니다.scripts/signals.tsv: 모든 탐지 및 시드 패턴;scripts/tools.tsv: 알고 있는 모든 분석기. 프로젝트는docs/agents/audit-signals.tsv에 자체 행을 추가합니다.scripts/verify.py: 발견 파일을 렌즈 파일과 비교 확인합니다.scripts/cochange.sh: 함께 변경되는 파일들.DELIVER.md: 인계 노트, 감사 맵 및 해당 티켓.UNTANGLE.md: 구조적 리팩터링,--untangle및 구조적 티켓용.
1. 범위
- 인수: 경로(기본값: 저장소 루트);
--lens a,b는 해당 렌즈만 실행;--since REF는 특정 참조(PR 베이스 또는 마지막 감사 커밋) 이후 변경 사항 감사;--fix;--untangle [area|ticket]은UNTANGLE.md로 바로 건너뜀;--out DIR(기본값.audit/). - 답변을 받을 수 없는 경우(CI,
claude -p), 답변되지 않은 질문은 열린 질문으로HANDOFF.md에 남고, 전달은 로컬 트래커로만 이루어지며, 소스는 티켓이approved:줄에 없으면 변경되지 않습니다. *를 포함하는.gitignore로 출력 디렉토리를 생성하여 감사가 추적된 파일을 건드리지 않도록 합니다. 새 실행을 시작할 때(재개할 때는 절대 안 함), 먼저 이전 실행의RUN.md,REPORT.md및findings/를<out>/history/<날짜>/로 이동하여 새 실행이 이전 실행과 비교할 수 있게 합니다.- 재개:
<out>/HANDOFF.md가 존재하면,next단계부터 계속하고 실행 파일을 그대로 둡니다.approved:줄의 티켓은 다시 묻지 않고 소스 변경이 허용됩니다;DELIVER.md에 명시된 대로 프론티어에서 첫 번째 티켓을 세션당 하나씩 작업합니다. 다른 티켓은 먼저 사용자에게 돌아갑니다. 이전 실행이history/에 존재하면,--since <해당 커밋>을 제안하고refuted.md를 전달합니다.
아래의 모든 단계는 DELIVER.md에 설명된 대로 <out>/HANDOFF.md를 다시 작성하여 종료됩니다.
2. 스캔 및 정찰
python3 scripts/scan.py <path> [--since REF] [--lens a,b] > <out>/SCAN.md를 실행하여 SCAN.md가 스크립트의 원시 출력이 되도록 합니다: 스택, 패키지, 실행되는 렌즈와 그 이유, 핫스팟, 실행 계획, 실행할 분석기, 프로브별 후보 사이트(가장 핫한 파일 우선), 특수 사례 개수.
도구 아래에 나열된 각 분석기 중 명령어를 사용할 수 있는 것을 실행하고 출력을 <out>/tools/<tool>.txt에 저장합니다. 해당 경고는 각 행이 명명하는 렌즈에 대한 단서이며 스캔 사이트와 동일합니다; 누락되었거나 실패한 도구는 RECON.md에 기록되며 설치되지 않습니다.
그런 다음 <out>/RECON.md를 작성하여 스크립트가 볼 수 없는 부분을 완료합니다. 모든 제목에 답변 또는 none이 있을 때만 완료합니다:
- 경계: 외부 데이터가 들어오는 모든 곳(HTTP, 웹훅, DB 읽기, 파일, 환경 변수, 딥 링크, 푸시 페이로드, 모델 출력, 사용자 입력).
- 지속성: 로컬 저장소, 서버 DB, 캐시, 큐, 그리고 각 사실을 소유하는 저장소.
- 중요 경로: 금전, 인증, 데이터 삭제, 마이그레이션, 안전 관련 사항, 주요 사용자 루프.
- 명령어: 빌드, 테스트, 린트, 실행; 테스트가 현재 통과하는지 여부.
- 하우스 규칙:
CLAUDE.md/AGENTS.md;GLOSSARY.md(또는GLOSSARY-MAP.md)의 도메인 언어는 발견 사항 및 수정 사항의 모든 이름에 사용됨; ADR, 수용된 위험은 위험이 변경되지 않는 한 유지됨;docs/agents/의 이슈 트래커. - 조건: 각 실행 렌즈에 대해, 여기서 충족되는 조건부 프로브와 증거.
- 렌즈 재정의: 스캔이 건너뛰었지만 정찰이 필요하다고 판단되는 렌즈, 또는 잘못된 신호로 실행된 렌즈와 그 이유.
<out>/RUN.md 작성: 커밋, 날짜, 인수, 최종 렌즈 목록.
3. 사냥
스캔의 계획을 따릅니다: 순차적은 각 렌즈를 여기서 차례로 실행합니다; 병렬은 각 렌즈에 서브에이전트를 할당하고, 샤딩된 렌즈는 나열된 각 패키지에 하나의 서브에이전트를 할당합니다. 동시성을 제한하는 호스트는 웨이브로 실행하며 사이트가 가장 적은 렌즈를 쌍으로 묶습니다; 서브에이전트가 없는 호스트는 모든 것을 순차적으로 실행합니다.
서브에이전트는 기술과 이 대화 내용 없이 시작되므로 각 브리프는 독립적입니다. 브리프는 다음을 명명합니다: 렌즈 파일, 이 파일(방법 및 발견 형식용), RECON.md, SCAN.md의 해당 렌즈 섹션, 범위, 출력 경로 <out>/findings/<lens>[-<package>].md. 헌터는 읽기 전용 리프(leaf)입니다: 코드를 읽고, 테스트, 스크립트 및 앱을 실행하며, 발견 파일과 재현(repro)만 작성하고, 메인 컨텍스트로 반환되며, 메인 컨텍스트만이 작업을 지시합니다.
방법
- 사후 분석(pre-mortem): 출시 3개월 후, 이 영역에 대한 최고의 1성 리뷰를 작성한 다음, 이를 유발한 코드를 찾습니다.
- 역전(inversion): 이 기능을 가능한 한 심하게 실패하게 만들려면 어떻게 하시겠습니까? 각 방법으로 코드 블록을 확인합니다.
- 가정 원장(assumption ledger): 중요 경로의 각 함수에 대해, 그것이 가정하는 것을 나열합니다. 어떤 것이 유형이나 제약 조건에 의해 적용되고, 어떤 것이 희망에 의존합니까?
- 체스터턴의 울타리(Chesterton's fence): 가드, 특수 사례 또는 이상한 줄을 버그라고 부르기 전에, 그것이 존재하는 이유를 찾습니다(
git log -L, 블레임, PR). 살아있는 이유가 있는 울타리는 발견 사항이 아닙니다. - 후보는 단서: 스캔 사이트는 읽기를 시작하는 곳입니다. 사이트가 0개인 프로브도 여전히 답변되며, 사이트는 구체적인 시나리오가 있을 때만 발견 사항이 됩니다.
발견 형식
### <LENS>-<n> <60자 미만의 주장>
- where: path:line
- probe: <렌즈 파일의 프로브 ID>
- scenario: <구체적인 입력, 상태 또는 타이밍> → <사용자 또는 시스템이 보는 잘못된 결과>
- severity: critical | high | medium | low
- detectability: loud (충돌, 경고, 테스트 실패) | quiet (누군가 알아차릴 수 있는 잘못된 답변) | silent (아무도 알아차리지 못함)
- verdict: CONFIRMED (재현한 <테스트, 스크립트, 쿼리 또는 스크린샷>) | PLAUSIBLE (추론됨, 실행되지 않음)
- fix family: <패치가 아닌 변경의 종류>
심각도: critical은 데이터를 잃거나 손상시키고, 보안이나 개인정보를 위반하며, 금전을 잘못 처리하거나 안전을 위험에 빠뜨립니다; high는 일반 경로에서 잘못된 답변을 보여주거나 사용자를 좌초시킵니다; medium은 드문 경로에서 그렇게 하거나 품질을 저하시킵니다; low는 위생 문제입니다. 심각도는 오늘날 출시된 구성에서 누가 트리거할 수 있는지에 따라 설정됩니다: critical 또는 high 시나리오는 그 사람(모든 방문자, 모든 로그인 사용자, X를 보유한 공격자)을 명명합니다; 운영자나 죽은 구성만이 도달할 수 있는 경로는 한 단계 낮춥니다.
수정(Redact): 발견 사항, 재현, 보고서 및 티켓은 공유됩니다. 비밀, 토큰 또는 개인 데이터 대신 <REDACTED>를 쓰고, 인용 대신 위치를 가리킵니다.
발견 파일은 렌즈의 산출물로 시작합니다. 모든 프로브는 최소 하나의 발견 사항 또는 하나의 clean: 줄로 끝납니다: clean: <probe> — <evidence>, 또는 조건이 충족되지 않는 조건부 프로브의 경우 clean: <probe> — n/a: <why>. 헌터는 완료 줄이 충족되고 python3 scripts/verify.py <out> --root <path> --lens <lens>가 통과하면 완료됩니다.
4. 검증
- 렌즈 간 중복 병합: 두 발견 사항이 위치와 메커니즘을 공유할 때, 더 심각한 블록을 유지하고
- also: <다른 ID>를 추가한 다음 다른 블록을 삭제하여 각 문제가 한 번만 나타나도록 합니다. - 반박: 모든 critical 또는 high 발견 사항은 새로운 반박자(refuter)를 받습니다; 나머지는 렌즈별로 일괄 처리됩니다. 반박자는 발견 블록만 받고 헌터의 추론은 받지 않습니다.
PLAUSIBLE발견 사항의 경우 주장을 무효화하려고 시도합니다: 업스트림 가드, DB의 제약 조건, 도달할 수 없는 경로, 이유가 있는 울타리.CONFIRMED발견 사항의 경우 재현을 확인합니다: 실제 사용자나 공격자가 도달하는 코드를 통해 명시된 이유로 빨간불이 켜집니까? 호스트가 다른 모델을 제공하면 반박자가 이를 사용합니다. 공유된 편향이 동일 모델 동의를 약한 증거로 만들기 때문입니다. - 증거에 의한 승격: 살아남고 재현됨 →
CONFIRMED; 추론으로 살아남음 →PLAUSIBLE; 무효화됨 → 이유와 함께<out>/refuted.md. - 커버리지 비평가: 하나의 새로운 서브에이전트가
RECON.md의 중요 경로와 모든 렌즈의clean:줄을 받고, 증거가 부족한(추적이나 테스트가 필요한 문장) 각 중요 경로 또는 어떤 렌즈도 도달하지 못한 경로를 지목합니다. 각각은 보고서 전에 일치하는 렌즈로 돌아가 두 번째 검토를 받습니다.
재현(repro)은 이 발견 사항에서만 빨간불이 켜지는 빠듯한 피드백 루프입니다: 가장 가까운 결합점(seam)에서 실패하는 테스트, 스크립트, 쿼리. 10분 미만이 소요되는 곳마다 <out>/repro/에 로컬, 브랜치, 샌드박스 또는 테스트 모드 시스템에 대해서만 하나를 만듭니다. 다음 분기까지 유효할 이유(수용된 위험, 의도적 트레이드오프)로 무효화된 발견 사항은 ADR에 속하며, 전달 시 제공되므로 나중 감사가 정찰에서 이를 읽습니다.
5. 보고
<out>/REPORT.md 작성:
- 요약: 심각도 및 렌즈별 개수, 그리고 먼저 수행할 세 가지 수정 사항과 그 이유.
- 수정 사항: 근본 원인별로 발견 사항을 클러스터링하고, 각 수정 사항은 그것이 해결하는 발견 사항 위에 작성합니다; 여러 발견 사항 뒤에 있는 하나의 수정 사항을 찾으십시오. 이는 종종 발견 사항과 전혀 닮지 않습니다. 각각을
structural(결합, 중복, 누락된 유형, 얕은 모듈, 잘못 배치된 결합점) 또는local(한 곳, 한 번의 변경)로 태그하고, 구조적 수정 사항을 심층 모듈 어휘로 설명합니다: module, interface, depth, seam, adapter, leverage, locality, deletion test. - 클러스터링되지 않은 발견 사항, 심각도, 그 다음 탐지 가능성(조용한 것 우선), 그 다음 도달 가능성 순으로 정렬.
- 커버리지: 모든 렌즈의
clean:줄, 건너뛴 렌즈와 그 이유, 실행되었거나 누락된 분석기, 커버리지 비평가가 보낸 내용. - 마지막 감사 이후,
history/에 이전 실행이 있는 경우: 수정됨, 여전히 열림, 새로 발견됨, 회귀됨(이전에 수정되었으나 다시 나타남).
- 서버를 `scan_count`의 유일한 작성자로 만들고, `where scan_count > 0`으로 원자적으로 감소시켜 클라이언트가 표류, 이중 사용 또는 재설정할 수 없도록 합니다. [structural, critical]
- MONEY-2 `ScanQuota.swift:40`은 업로드 전에 로컬로 감소하고 재시도 시 다시 감소합니다.
- MONEY-3 앱 재설치는 로컬 저장소의 `scansUsed`를 0으로 재설정합니다.
- STATE-5 주간 할당량은 기기의 로컬 월요일에 재설정되므로 서쪽으로 비행하면 두 번째 주가 부여됩니다.
python3 scripts/verify.py <out> --root <path>를 실행합니다; 보고서는 통과할 때 최종입니다. 호스트가 구조화된 발견 사항(ReportFindings 도구)을 렌더링하는 경우, 가장 심각한 것부터 시작하여 살아남은 모든 발견 사항도 거기에 보고합니다.
이 프로젝트에 대한 까대기 조정(tune) : 모든 사이트가 반박되거나 깨끗한 것으로 끝난 시드 행, 또는 어떤 시드도 가리키지 않은 발견 사항은 프로젝트의 docs/agents/audit-signals.tsv에 대한 제안 행입니다. 보고서에 제안을 나열합니다; 사용자가 수락할 때만 작성됩니다.
6. 전달 및 인계
DELIVER.md를 읽습니다. 보고서를 수정 사항당 하나의 티켓이 있는 감사 맵으로 차트화하고, 차단 에지(blocking edge)를 포함하여 입력하고, 저장소의 이슈 트래커(구성된 항목이 없으면 로컬 .scratch/; 원격 트래커에 게시하기 전에 확인)에 입력합니다. 그런 다음 하나의 grilling 라운드로 시작할 수정 사항을 묻습니다: 각각을 권장 답변과 함께 질문으로 번호를 매기고, "예"가 수락하도록 표현합니다. --fix를 사용하면 모든 권장 사항을 수락합니다. 승인된 티켓 번호를 HANDOFF.md의 approved: 줄에 기록합니다.
각 티켓을 그 형태에 따라 라우팅합니다. 명명된 기술은 mattpocock-skills입니다; Skill 도구를 사용할 수 있으면 호출하고, 그렇지 않으면 단계를 인라인으로 수행합니다:
| 티켓 형태 | 경로 |
|---|---|
| 먼저 결정이 필요한 경우: 결합점이 어디에 있어야 하는지, 모순되는 ADR, 모호한 도메인 용어, 수용할 위험 | grill-with-docs, 답변을 ADR 및 용어집 용어로 기록함 |
| 구조적, 하나의 모듈, 커밋 전에 사용자와 탐색할 가치가 있음 | 해당 영역의 improve-codebase-architecture |
| 구조적, 경쟁하는 인터페이스 디자인 | codebase-design, 디자인-두-번 패턴 |
| 구조적, 방법이 명확하고 한 세션에 맞음 | UNTANGLE.md, 티켓과 REPORT.md를 시작 목록으로 사용 |
| 구조적, 한 세션보다 큼 | wayfinder, 목적지를 향한 결정 티켓 차트 작성 |
| 무인 작업을 위한 에이전트 분할을 위한 많은 수정 사항 | to-tickets (트레이서-불렛 슬라이스, 차단 에지, 확장-축소로서의 넓은 리팩터), 그 다음 implement |
| 로컬 수정 | tdd: 재현은 사용자와 동의한 결합점에서 첫 번째 빨간 테스트입니다; 전체 스위트는 녹색을 유지합니다 |
PLAUSIBLE이고 critical이며, 아직 재현 없음 | diagnosing-bugs 1단계: 먼저 빠듯한 루프 구축 |
프론티어가 비어 있으면 --since <감사 커밋>으로 재감사합니다. 감사의 목적지는 살아남은 critical 또는 high 발견 사항 없이 검증하는 재감사입니다.
완료 조건
- 모든 실행 렌즈가 완료 줄을 충족하는 발견 파일을 가지고 있고,
verify.py가 전체 출력에 대해 통과합니다. - 모든 살아남은 발견 사항에는 위치, 프로브, 시나리오, 심각도, 탐지 가능성 및 평결이 있습니다; 모든 무효화된 발견 사항은
refuted.md에 있습니다. REPORT.md는 모든 발견 사항을 수정 사항 아래 또는 클러스터링되지 않은 목록에 배치하고, 맵은 수정 사항당 하나의 티켓을 보유하며,HANDOFF.md는 다음 티켓을 명명합니다.