문서와 심볼

aidlc-docs 를 그대로 읽는다 · 읽기 전용
/home/sunny/enode-fixup-workshop2-visualizer연결 중
inception/reverse-engineering/code-structure.md268 줄

enode — 코드 구조

f46e187 시점의 계측. 수치는 전부 이 저장소에서 직접 재었다.

전체 계측

항목 값
Go 파일 100 (비테스트 67 · 테스트 33)
총 LOC 27,211 (비테스트 17,288 · 테스트 9,923)
패키지 15 (cmd/ 5 · internal/ 10)
Go 버전 go 1.26 하한 · toolchain go1.26.6
모듈 github.com/taeels/enode
Makefile 없음. 코드 생성 없음. 벤더링 없음

디렉터리 배치

   enode/
   ├── cmd/                  실행파일 다섯
   │   ├── enode/            노드 상주 프로세스        3 파일  269줄
   │   ├── enodectl/         한 기계의 인스턴스 관리   4 파일  531줄
   │   ├── mediator/         중앙 서버                 2 파일  405줄
   │   ├── runctl/           사용자 CLI (무상태)       1 파일  423줄
   │   └── iapadapter/       It's a Plan 어댑터        7 파일 2,436줄
   ├── internal/             라이브러리 열
   │   ├── api/              Mediator HTTP 표면        1+1    4,172줄
   │   ├── store/            PostgreSQL 상태 저장소   12+2    4,787줄
   │   ├── contract/         계약 · 광고 타입          5+3    3,565줄
   │   ├── enode/            노드 런타임              25+20   8,254줄
   │   ├── match/            요구 → 노드 (순수 함수)   1+1      408줄
   │   ├── record/           Run Record (파일시스템)   1+1      676줄
   │   ├── schema/           형식 전용 JSON Schema     1+1      339줄
   │   ├── config/           Mediator 설정 (YAML)      2+1      481줄
   │   ├── runctl/           runctl HTTP 클라이언트    1+1      345줄
   │   └── build/            버전 한 줄                1+1      120줄
   ├── packaging/            deb · rpm · msi · macos
   ├── scripts/testdb.sh     테스트용 Postgres 도커
   └── .github/workflows/    ci.yml · package.yml · release.yml

파일 수는 비테스트+테스트 표기다. 줄 수는 테스트 포함이다.

파일 분류

실행 진입점 (5)

cmd/*/main.go 다섯. 전부 [no test files] 상태다.

  • cmd/mediator/main.go — 설정 로드 → 토큰 부트스트랩 → store.Open →
    Migrate → reaper 고루틴 → http.Server. WriteTimeout 을 일부러 걸지
    않는다(claim 롱폴 최대 2시간)
  • cmd/enode/main.go — 신원 유도 → 로컬 잠금 → 광고 고루틴 + claim 워커
    고루틴 두 개
    . --once · --ready-file 이 탄력 노드용
  • cmd/enodectl/main.go — 프로세스 관리. 셸판이 node_id 를 다시 계산하던 것을
    없애려고 Go 로 옮겼다
  • cmd/runctl/main.go — 무상태. permute() 가 플래그를 앞으로 모아
    runctl submit x.json --wait 같은 순서를 받는다
  • cmd/iapadapter/main.go — 바깥(이슈 트래커)을 아는 유일한 부품

도메인 어휘 (1 패키지)

internal/contract — 넷의 공통 어휘. contract.go(1,724줄) · grammar.go ·
checkplan.go · planshape.go · advert.go.

순수 함수 (2 패키지)

I/O 가 0인 것 둘. 테스트하기 가장 쉽고 실제로 가장 잘 덮여 있다(97.5% · 75.7%).

  • internal/match — 요구 대 광고를 받아 배정표 또는 거절 코드를 돌려준다
  • internal/schema — 형식 전용 JSON Schema 검증기. CheckBoundary 가
    minimum · minLength 같은 품질 판정 키워드를 계약 단계에서 거절한다

상태와 영속 (2 패키지)

  • internal/store — PostgreSQL. 12개 비테스트 파일이 동사별로 갈려 있다:
    store.go(생성 · 열기) · claim.go(배분 · 보고) · acquire.go ·
    release.go · dispatch.go · expand.go · rollback.go · seal.go ·
    observe.go · ask.go · reap.go · verdict.go. 매칭 로직은 여기 없다
  • internal/record — Run Record. DB 가 아니라 파일시스템(chmod 0444/0555
    봉인) · blob · tar

표면 (2 패키지)

  • internal/api — 15개 라우트가 api.go 한 파일(830줄)에 전부 있다
  • internal/runctl — runctl 의 HTTP 클라이언트. 12개 메서드

노드 런타임 (1 패키지, 25 파일)

internal/enode 가 이 저장소에서 파일 수가 가장 많은 패키지다.

   신원 · 잠금    identity.go  repoid.go  lock.go  lock_unix.go  lock_windows.go
   탐지 · 광고    detect.go  advertise.go  leases.go
   실행           claim.go(873줄)  runner.go  argv.go  agent.go
   하네스         harness.go  claude.go
   환경           env.go  config.go  paths.go
   워크스페이스   workspace.go  setup.go  diff.go  changed.go
   수거           collect.go  hook.go
   디스크         disk_unix.go  disk_windows.go

OS 분기는 _unix.go / _windows.go 빌드 태그 쌍 둘(lock · disk)로만
처리한다.

설정과 부수 (2 패키지)

  • internal/config — Mediator 설정(YAML). 사용자 경로가 /etc 를 이긴다
  • internal/build — <cmd> --version 한 줄. 링커가 박거나 Go VCS 스탬프에서
    읽는다

내부 의존 그래프

단방향이고 순환이 0건이다.

flowchart TD
    CMDMED["cmd/mediator"]
    CMDEN["cmd/enode"]
    CMDECTL["cmd/enodectl"]
    CMDRC["cmd/runctl"]
    CMDIAP["cmd/iapadapter"]
    API["internal/api"]
    ST["internal/store"]
    ENL["internal/enode"]
    RCL["internal/runctl"]
    CT["internal/contract"]
    MT["internal/match"]
    RD["internal/record"]
    SC["internal/schema"]
    CF["internal/config"]
    BD["internal/build"]

    CMDMED --> API
    CMDMED --> ST
    CMDMED --> RD
    CMDMED --> CF
    CMDMED --> BD
    CMDEN --> ENL
    CMDEN --> BD
    CMDECTL --> ENL
    CMDECTL --> BD
    CMDRC --> RCL
    CMDRC --> BD
    API --> ST
    API --> MT
    API --> RD
    API --> SC
    API --> CT
    API --> CF
    ST --> CT
    ST --> MT
    ST --> RD
    ENL --> CT
    MT --> CT

cmd/iapadapter 는 그래프에 간선이 없다. 내부 패키지를 하나도 import 하지 않고
자기 안에서 HTTP 로 Mediator 와 말한다.

경계 — internal/enode 는 internal/store 와 internal/api 를 못 본다

이 저장소에서 가장 중요한 구조적 사실이다.

   internal/enode  ──import──▶  internal/contract     (import 하는 것은 이것뿐)
   internal/enode      import 안 함     internal/store
   internal/enode      import 안 함     internal/api

노드가 Mediator 내부를 못 보는 것이 규약이 아니라 컴파일러가 지키는 사실이다.
노드는 Mediator 를 HTTP 표면으로만 안다. 노드 코드에서 Mediator 의 상태 표현을
직접 만지려는 시도는 컴파일이 안 된다.

같은 방향으로 internal/store 도 internal/api 를 모른다. 의존은 언제나
바깥(표면)에서 안(상태)으로만 흐른다.

코드 패턴

doc comment 가 「왜」를 적는다

이 저장소에서 가장 두드러지는 성질이다. 거의 모든 패키지 · 타입 · 함수에 doc
comment 가 붙어 있고, 그 내용이 「무엇을 한다」가 아니라 왜 이 형태인가 · 어떤
대안을 왜 기각했나 · 어떤 실측이 이것을 고치게 했나
다. 실측 사례가
식별자(vm-scratch-7 · zephyr-setup-8 · colima-enode-1 · third-run-1 ·
reject-3 · rewind-1)와 함께 인용되는 자리가 20곳 이상이다.

internal/store/schema.sql 은 스키마 파일이라기보다 주석이 절반 이상인 설계
문서에 가깝다 — 각 컬럼이 왜 있는지, CHECK 을 왜 안 거는지가 적혀 있다.

ADR-NNN 을 코드에 인용한다

ADR-\d{3} 이 Go 소스에서 55개 서로 다른 번호로 인용된다. 결정과 코드
사이의 역추적이 grep 하나로 된다.

오류를 삼킬 때 이유를 적는다

//nolint: 지시자 28곳은 전부 errcheck 이고 거의 다
defer f.Close() · defer tx.Rollback(ctx) 형태이며, 여럿에 이유 주석이 붙어
있다. _ = 로 오류를 버리는 39곳도 대부분 옆에 근거가 적혀 있다.

「자리만 파 둔 것」을 주석으로 표시한다

TODO 를 안 쓰는 대신 doc comment 로 적는다.

  • internal/store/seal.go:95 ByMediator = "mediator" — "아직 안 쓴다",
    실제 참조 0건
  • internal/enode/env.go:60 RunIdentity — "지금은 아무도 안 본다. 자리를
    파는 이유는…"(R2 요청자 신원용)
  • internal/enode/env.go:88 Transparent{} — 아무것도 주입 안 하는
    Credentials 구현. 의도적으로 nil 대신 타입을 둔 것을 주석이 적는다

큰 함수 · 큰 파일

함수 줄 위치
applyExpands 273 internal/store/expand.go:52
run 250 cmd/runctl/main.go
Worker.execute 222 internal/enode/claim.go:383
buildPrompt 210 internal/enode/agent.go:186
Verify 194 internal/store/verdict.go:98
runSetup 185 cmd/mediator/setup.go
RenewLeases 182 internal/store/claim.go:38
main 173 cmd/enode/main.go
Contract.Validate 612 internal/contract/contract.go:954
파일 줄
internal/api/api_test.go 3,342 (테스트 78개 단일 파일)
internal/contract/contract.go 1,724
internal/store/claim.go 938
internal/enode/claim.go 873
internal/api/api.go 830

표기 규약 — 저장소 고유

CLAUDE.md(72줄)가 두 규약을 세운다.

  1. 장식 문자를 안 쓴다. 강조는 마크다운 **굵게** 만. 코드 · 주석 ·
    문자열 · 로그 · 테스트 메시지 · 프롬프트 · 설정 어디에도 넣지 않는다.
    CI 가 집행하는 것은 U+2605(검은 별) 하나뿐이고 현재 0건이다
  2. 밖으로 나가는 것은 영어, 안 나가는 것은 한국어. 기준이 「코드냐」가
    아니라 「밖으로 나가느냐」다 — 에러 문자열 · 로그 · CLI 출력 · 테스트 이름 ·
    픽스처 · 에이전트 프롬프트는 영어, 주석 · 커밋 메시지 · testdata 는 한국어.
    제품이 실행 중에 자기 언어를 에이전트에 재주입하는 되먹임을 끊는다는 근거가
    같은 문서에 적혀 있다

두 규약과 실제 코드 사이의 관측된 틈은 code-quality-assessment.md 에 적었다.

테스트 배치

전용 테스트 디렉터리가 없다. Go 관례대로 각 패키지 안에 *_test.go 로 함께
산다. internal/contract/testdata/ 가 유일한 픽스처 디렉터리다.