아키텍처 결정을 lint로 쓰세요
같은 AGENTS.md 안에서, 명령이 있는 규칙은 운영체제 세 대에서 빨갛게 켜져요. 경로만 있는 그 조항은, 이름을 바꾼 뒤에도 아무도 모릅니다.
- 호출점 인자가 익명 리터럴인가lib.rs L261
- 주석 이름이 매개변수 이름과 같은가lib.rs L222
- 피호출이 workspace crate인가lib.rs L177
- CI가 세 플랫폼에서 동시에 도는가rust-ci.yml L174
- Markdown 경로가 아직 존재하는가AGENTS.md L35
- Feature가 망라 표에 등록되었는가lib.rs L379
- 개발 중 특성은 기본이 꺼져 있어야 해요tests.rs L18
신입이 일을 받아요. MCP 도구 호출을 고치라는 거예요. AGENTS.md를 열고 35행의 경로를 베껴요. 파일이 없어요. 진짜 파일은 connection_manager.rs이고, 같은 디렉터리에 있어요. 문서의 mcp_ 접두 이름은, 한번 이름을 바꾼 뒤 청소하지 않은 잔여예요.
출처:AGENTS.md 32–36행;codex-rs/codex-mcp/src/connection_manager.rs 1–15행
같은 파일에서, 위치 매개변수에 /*base_url*/이 빠지면 로컬 명령이 빨개져요. Cargo.toml을 고치고 Bazel 락을 안 새로고치면 CI가 빨개져요. 35행 그 경로에는 검사기가 없어요. Markdown은 파일이 있는지를 스스로 대조하지 않아요.
먼저 API를 바꿔, 호출점 스스로 읽히게 하세요. foo(false)의 독자는 정의로 뛰어가야 이 false가 무엇을 다스리는지 알아요. API를 못 바꿀 때만 /*param_name*/을 허용해요. lint는 퇴로예요.
출처:AGENTS.md 14–20행
구현은 독립 Dylint 크레이트에 살며, rustc 한 번으로 돌아요. 타입 해석이 끝난 뒤에야 피호출의 매개변수 이름을 얻어요. 입구는 함수 호출과 메서드 호출만 보고, 매크로가 펼친 것은 바로 건너뛰어요.
검사는 이 순서로 가요.
1. 이 저장소 crate만 봐요. std와 tokio는 바로 통과예요.
2. 주석은 세 곳에서 찾아요. 인자 앞 틈, 앞 64바이트, 인자 텍스트 자신.
3. 이름이 틀리면 mismatch예요. 잘못된 주석은 “주석 없음” 조항으로 다시 떨어지지 않아요.
4. 안 썼을 때, 메서드 이름이 유일한 매개변수 이름과 같으면 면제예요. 예: .enabled(false).
5. 나머지는 익명 리터럴만 막아요. None, 불리언, 숫자는 써야 하고, 문자열과 문자는 통과예요.
출처:tools/argument-comment-lint/src/lib.rs 165–180행;tools/argument-comment-lint/src/lib.rs 261–274행
저장소 입구는 기본 Allow인 그 조항을 deny로 올려요. CI는 Linux, macOS, Windows에서 각 한 번 돌고, 한 대가 실패해도 나머지 두 대는 끝까지 가요. 사람이 macOS에서 초록이어도, Windows 대상의 매크로 전개가 None을 하나 더 내면 세 번째 기계가 여전히 막아요.
출처:.github/workflows/rust-ci.yml 164–187행
호출점은 국소적이고, 이름은 해석할 수 있고, 오탐은 면제로 거둘 수 있어요. 언어를 바꿔도 모양은 같아요. 먼저 이름을 고치고, 못 고치면 줄 안 이름을 요구해요. TypeScript는 ESLint, Python은 ruff, 둘 다 맞아요.
35행과 265행은 같은 부패예요. app-server 안내서는 아직 v2.rs를 쓰고, 지금은 디렉터리 v2/이며 아래가 서른 개 넘는 파일로 갈라졌어요. 파일이 800줄에 가까우면 쪼개야 해요. 쪼갠 뒤, 안내서의 단일 파일 경로는 아무도 안 바꿨어요.
출처:AGENTS.md 260–266행
모듈 줄 수 규칙은 자주 쓰는 파일 다섯을 지목해요. 넷은 이미 800을 넘었고, 하나는 900에 붙어 있어요. chat_composer.rs는 줄로 치면 12859줄이에요. 저장소에는 줄을 세는 명령이 없어요. 줄은 셀 수 있지만 CI는 세지 않아요. 한 변경이 기계적인지는 기계가 잘 못 하니, 800줄 상한은 리뷰에서 멈춰요.
출처:AGENTS.md 49–61행;AGENTS.md 125–131행
규칙을 두 세트로 읽으세요. 한 세트는 명령이나 컴파일러가 있어, 병합 전에 빨개져요. 한 세트는 사람과 리뷰만 읽고, 놓치면 통과예요. 경로 존재는 원래 가장 쉬운 검사예요. 백틱 경로를 뽑아 저장소 루트에 존재 여부를 보면 돼요. 저장소는 안 했어요. 예산은 호출점 가독성에 썼고, 경로 존재에는 안 썼어요.
문서는 스스로 재검사하지 않아요. 국소 검사할 수 있는데 Markdown에만 쓰면, 이름을 바꾸거나 파일을 쪼갠 날 글자는 남고 대상은 이사해요. 최소 형태는 경로를 대조하는 스무 줄 스크립트예요. rustc 플러그인은 필요 없어요.
특성 스위치가 불리언과 설명 한 편에만 기대면, 등록 누락, 개발 중 기본 켜짐, 그냥 앉아 있는 Deprecated는 바로 빨개지지 않아요.
Feature 열거형 옆에 FEATURES 표가 있어요. FeatureSpec은 식별자, 설정 키, 단계, 기본 켜짐을 한 줄에 용접해요. 표에서 짝을 못 찾으면 unreachable!예요. 열거형에 변체가 하나 늘고 표에 한 줄이 빠지면, key()까지 가서 바로 붕괴해요.
출처:codex-rs/features/src/lib.rs 41–58행;codex-rs/features/src/lib.rs 819–826행;codex-rs/features/src/lib.rs 379–384행
옆의 테스트 두 개가 기본값을 잠가요. 개발 중 특성은 기본이 꺼져 있어야 해요. 기본이 켜진 특성의 단계는 Stable 또는 Removed여야 해요. 단계는 다섯이고, 여분의 Experimental은 메뉴 이름과 공고를 달고 있어요. Deprecated에는 만료일이 없고, Deprecated 항목 셋은 여전히 켤 수 있어요. 단계는 “더는 쓰지 마”는 말할 수 있어도, “다음 버전에 지워”는 말 못 해요.
출처:codex-rs/features/src/tests.rs 17–28행;codex-rs/features/src/tests.rs 82–94행
망라 표 더하기 테스트 두 개는, 언어를 바꿔도 성립해요. 등록이 빠지면 붕괴하고, 기본값은 잠겨요. 자동 삭제는 못 얻고, 이 불변식 둘만 얻어요.
DSH: 모든 패키지가 모습을 보여야 하고, 비어도 설명을 해야 해요
DeepSeek Harness는 “모든 패키지는 ./invariant를 가져야 한다”를 산문과 문으로 동시에 써요. 산문은 packages/AGENTS.md에 있어요. 문은 21줄 verify-package-invariants이고, 실패하면 process.exit(1)예요. 빈 설치기는 고정 접두 No runtime invariant:를 달아야 해요. 빔은 명시적 아키텍처 결론이에요. 나중에 가변 상태를 들이면, 진짜 검사로 바꿔야 해요.
노트는 왜 빔을 허용하는지 답하고, 검사기는 빔이 반드시 설명되어야 함을 보장해요. 둘 중 하나가 빠지면 Codex 35행 그 상태로 돌아가요. 글자는 남고, 대상은 이미 이사했어요. DSH에는 foo(false)를 보는 rustc 플러그인이 없어요. Codex에는 경로 존재를 보는 망라식 패키지 문이 없어요.
출처:packages/AGENTS.md 18행;scripts/verify-package-invariants.ts 1–21행
Grok: 국소화할 수 있는 결정은 clippy에 바로 넣어요
Grok Build 저장소 루트에는 AGENTS.md가 없어요. 그래도 아키텍처 결정 하나를 lint로 써요. clippy.toml이 canonicalize를 금하는 이유는, Windows에서 verbatim 접두가 나와 git을 깨고 모델 컨텍스트로 새기 때문이에요. 실행 경계도 같은 파일에 있어요. 이 금지는 각 crate의 cargo clippy presubmit가 돌리고, Bazel만 타는 crate는 사람이 봐야 해요.
Codex의 매개변수 주석과 같은 종류의 판단이에요. 호출점은 국소적이고, 오탐 면은 통제할 수 있어요. Grok은 Bazel 커버가 불완전하다고 인정해요. Codex는 로컬이 현재 OS만 돈다고 인정해요. 작은 팀은 경로 존재와 21줄 verify 스크립트를 먼저 베끼는 편이, Dylint를 베끼는 것보다 싸요.
출처:clippy.toml 9–28행
어떤 자동 검사를 먼저 만들까요
AGENTS.md 35행과 265행은 둘 다 죽은 경로예요. 자동 검사를 하나만 먼저 만들 수 있다면, codex-rs/ 접두 경로를 볼까요, 아니면 백틱 안에 /가 있는 모든 문자열을 볼까요?
첫 번째는 app-server-protocol/src/protocol/v2.rs 같은 상대 표기를 놓쳐요. 두 번째는 명령 이름, crate 이름, URL 조각을 다치게 해요. 필터 규칙을 쓰고, 이 죽은 경로 둘을 양성 예로 쓰세요.