enode — 코드 품질 평가
이 문서의 첫 절이 이번 스캔의 가장 큰 발견이다. 워크플로가 들고 있던
커버리지 기준선이 틀렸고, 그것이 「테스트 공백이 어디인가」의 답을 통째로
바꾼다. 뒤의 어떤 절보다 먼저 읽어야 한다.
계측치 정정 — 이전 커버리지 수치가 왜 틀렸나
무슨 일이 있었나
이 워크플로가 들고 있던 패키지별 커버리지 수치는 go test ./... -cover 를
ENODE_TEST_DATABASE_URL 없이 돌려 얻은 것이다.
internal/api/api_test.go:33 과 :339 가 그 환경변수가 없으면 스위트 전체를
t.Skip 한다.
t.Skip("ENODE_TEST_DATABASE_URL is unset — see scripts/testdb.sh")
그래서 이전 수치는 78개 통합 테스트가 통째로 안 돈 상태의 것이었고,
internal/api 가 0.0% 로 보였다.
왜 미래의 독자가 같은 실수를 반복하는가
이 저장소에서 go test ./... -cover 를 아무 준비 없이 돌리면 아무 오류 없이
통과한다. 78개가 조용히 사라지는데 종료코드는 0 이다. 그래서 수치가 틀렸다는
신호가 어디에도 뜨지 않는다. 다시 재는 사람은 반드시 두 가지를 해야 한다.
scripts/testdb.sh로 Postgres 17 을 띄우고ENODE_TEST_DATABASE_URL을 넣는다-coverpkg=./...로 교차 커버리지를 잰다 (아래 참조)
CI 는 이 함정을 알고 있어서 internal/api 에 SKIP 이 한 줄이라도 나오면
실패시키는 전용 단계를 따로 둔다(ci.yml 의 "DB 테스트가 스킵되지 않았는지").
로컬에는 그 방어가 없다.
internal/store 의 5.5% 가 왜 거짓인가
internal/store 는 자기 패키지 기준으로 5.5% 로 나온다. 그 이유는
internal/store 의 테스트 파일 둘(verdict_test.go · seal_manifest_test.go)이
DB 를 안 쓰는 순수 단위 테스트이기 때문이다.
store 를 실제로 도는 것은 internal/api 의 78개 통합 테스트이고, Go 의
패키지별 커버리지는 그 교차 실행을 계산에 넣지 않는다.
-coverpkg=./... 로 다시 재면 internal/store 는 81.0% 이고,
90개 함수 전부가 테스트에 한 번 이상 들어간다.
커버리지 — 교차 측정 (-coverpkg=./..., DB 붙임)
97.5% internal/match
88.5% internal/contract
81.5% internal/record
81.0% internal/store (패키지별 측정의 5.5% 가 아니다)
75.7% internal/schema
75.0% internal/build
67.5% internal/enode
65.2% internal/api (DB 없이 재면 0.0%)
55.9% internal/config
37.0% internal/runctl
19.1% cmd/iapadapter
0.0% cmd/enode · cmd/enodectl · cmd/mediator · cmd/runctl
─────
58.6% 전체 (3,485 / 5,951 statements)
internal/store 파일별 (교차, 문장 기준)
97.5% verdict.go 86.2% release.go 84.7% seal.go
84.5% claim.go 82.0% rollback.go 80.5% store.go
80.0% expand.go 79.6% ask.go 78.9% observe.go
77.0% dispatch.go 76.0% acquire.go 66.7% reap.go
reap.go 66.7% 가 store 내부 최저이고, 안 덮인 부분은 주로 sealExpired 의
오류 분기다.
실제 테스트 공백 — 우선순위
정정된 계측이 「가장 안 덮인 자리」의 위치를 바꾼다. internal/store 가
아니다.
1. cmd/ 네 실행파일 — 0%, 682 statements
| 파일 | statements | 안 덮이는 것 |
|---|---|---|
cmd/runctl/main.go |
224 | 하위명령 디스패치 · 플래그 permute · 4단 종료코드 판정 |
cmd/enodectl/main.go |
194 | 프로세스 관리(start · stop · logs · status) |
cmd/mediator/setup.go |
154 | runSetup(185줄) — 초기 설정 생성 |
cmd/enode/main.go |
80 | 이중 고루틴 수명 관리 · --once 종료 판정(:170-190) · instance 생성(:120-128) |
cmd/mediator/main.go |
57 | 부팅 순서 · 설정 해석 · 토큰 부트스트랩 · reaper 기동 · graceful shutdown |
cmd/enode/hook.go |
22 | 종료 훅 진입점(어떤 실패에도 종료코드 0) |
부팅 순서 · 설정 해석 · 토큰 부트스트랩 · reaper 기동 · graceful shutdown ·
이중 고루틴 수명 · --once 종료 · 프로세스 관리가 전부 여기 있고 전부
0% 다.
2. internal/enode/claim.go — 24.8% (322 중 80)
S4 위험의 노드 쪽 절반이 여기다. 873줄짜리 워커 실행 경로이고,
internal/enode 패키지 안에서 압도적으로 가장 안 덮인 파일이다 — 같은 패키지의
다른 파일은 대부분 75~96%.
이 파일이 들고 있는 것:
execute (claim.go:383, 222줄)
runAgentStep (123줄)
uploadProduced (:728)
report 재시도 루프 (:309, 닿을 때까지 재시도)
임대 워치독 고루틴 (:498-514)
execute 하나가 임대 워치독 고루틴 · $IN 적재와 sealInput · argv 확장 ·
명령 단계 실행 · 로그 업로드 순서를 전부 들고 있다.
README.md:34 가 S4 를 최대 위험으로 지목한 것과 계측이 같은 곳을 가리킨다.
3. cmd/iapadapter — 19.1%
itsaplan.go 0.0%
main.go 10.1%
orchestrator.go 14.5%
바깥 트래커와 말하는 경로가 거의 안 덮여 있다.
4. internal/enode 의 나머지 저커버 파일
paths.go 48.6%
leases.go 52.4% (임대 보유 상태 — S4 와 인접)
diff.go 58.9%
workspace.go 61.4%
setup.go 64.7%
5. internal/runctl/client.go — 37.0%
12개 메서드 중 4개만 테스트에 들어간다.
테스트 구성
배치
전용 테스트 디렉터리가 없다. Go 관례대로 각 패키지 안에 *_test.go 로 함께
산다. 33개 파일에 306개 테스트 함수, 11개 패키지에 분포한다.
| 패키지 | 테스트 함수 | 파일 |
|---|---|---|
internal/enode |
137 | 20 |
internal/api |
78 | 1 (3,342줄) |
internal/contract |
32 | 3 |
internal/store |
13 | 2 |
cmd/iapadapter |
13 | 1 |
internal/record |
10 | 1 |
internal/match |
9 | 1 |
internal/config |
5 | 1 |
internal/runctl |
4 | 1 |
internal/schema |
3 | 1 |
internal/build |
2 | 1 |
| 합계 | 306 | 33 |
cmd/enode · cmd/enodectl · cmd/mediator · cmd/runctl 넷은
[no test files] 다.
없는 테스트 종류
벤치마크 · 퍼즈 · Example 테스트가 0건이다 (계측 확인:
grep -rhoE '^func (Benchmark|Fuzz|Example)' --include='*_test.go' → 0).
internal/schema 의 JSON Schema 파서와 internal/contract 의
Validate()(612줄)가 퍼즈의 자연스러운 대상인데 하나도 없다.
프레임워크
표준 testing 만. assertion 라이브러리도 mock 라이브러리도 없다.
internal/api/api_test.go 는 mock 대신 실제 PostgreSQL 을 띄워 httptest 로
서버를 세우는 통합 스위트다.
커버리지 설정
부재. 커버리지 임계선을 강제하는 설정이 없고, CI 에 커버리지를 재는 단계도
없다. 위의 수치는 전부 이번 스캔에서 손으로 잰 것이다.
실행 시간
internal/enode— 약 29초 (전체 스위트의 사실상 전부)internal/api— DB 가 붙으면 약 4.9초
스킵 조건 전수 (t.Skip 호출 16곳)
| 조건 | 곳 | 위치 |
|---|---|---|
| 심볼릭 링크 생성 불가 | 3 | internal/enode/collect_test.go:77,101,121 |
sh 부재 |
3 | internal/enode/env_test.go:106,139,184 |
ENODE_TEST_DATABASE_URL 부재 |
2 | internal/api/api_test.go:33,339 |
| packaging 예시 부재 | 2 | internal/enode/examples_test.go:19,64 |
| root 로 실행 | 1 | internal/enode/collect_test.go:223 |
claude 미설치 |
1 | internal/enode/claude_test.go:111 |
| 하네스도 저장소도 없음 | 1 | internal/enode/enode_test.go:152 |
| 홈 디렉터리 부재 | 1 | internal/enode/paths_test.go:34 |
git 사용 불가 |
1 | internal/enode/workspace_test.go:157 |
| 자식 프로세스 스폰 불가 | 1 | cmd/iapadapter/adapter_test.go:272 |
가장 위험한 것은 ENODE_TEST_DATABASE_URL 두 곳이다 — 그 둘이 78개를
조용히 없앤다. CI 만이 그것을 잡는다.
정적 검사와 CI/CD
강제되는 검사
golangci-lint 설정이 없다. 강제되는 것은 셋이다.
gofmt -l .가 비어 있어야 통과go vet ./...- 저장소 고유 검사 —
.github/workflows/ci.yml의 「장식 문자가 없는지」
잡이grep -rlIP '\x{2605}'로 저장소 전체에서 U+2605 를 찾아 하나라도 있으면
실패시킨다. 현재 0건
//nolint: 지시자는 28곳이고 전부 errcheck 이며, 거의 다
defer f.Close() · defer tx.Rollback(ctx) 형태다(여럿에 이유 주석이 붙어 있다).
워크플로 3개
ci.yml — push(main) · pull_request 트리거. 잡 둘.
test 잡은 Postgres 17 서비스 컨테이너를 띄우고 ENODE_TEST_DATABASE_URL 을
넣은 뒤 여섯 단계를 돈다.
① go version
② 장식 문자가 없는지 (U+2605 검사)
③ gofmt -l .
④ go vet ./...
⑤ go test ./... -count=1
⑥ DB 테스트가 스킵되지 않았는지 (internal/api 에 SKIP 이 없는지 확인)
⑥ 이 이 저장소의 가장 좋은 CI 장치다 — DB 테스트가 조용히 사라지는 것을 막는
전용 단계이고, 이번 스캔이 정정한 바로 그 함정을 겨눈다.
cross 잡은 GOOS=windows/amd64 · linux/arm GOARM=7 · darwin/arm64 로
go build ./... 를 돌린다. Go 버전은 go-version-file: go.mod 로 한 곳에서만
온다.
package.yml — 172줄. packaging-experiment 브랜치 push ·
workflow_dispatch · workflow_call 셋으로만 돈다(커밋마다 돌지 않는다).
잡 셋: build(deb · rpm · msi 를 리눅스에서 굽는다, msi 는 wixl) ·
verify-linux(실제로 설치해 본다) · verify-windows.
release.yml — v* 태그 push. 자기 빌드를 짓지 않고 package.yml 을
workflow_call 로 그대로 부른다. 검증 잡이 전부 초록일 때만 publish 가 돈다.
CI 에 없는 것
- 커버리지 측정 단계 없음
- 커버리지 임계선 없음
- golangci-lint 없음
- 보안 스캐너(
govulncheck·gosec) 없음 - 의존 취약점 검사 없음
문서화 품질
강점 — doc comment 가 「왜」를 적는다
이 저장소에서 가장 두드러지는 성질이다. 거의 모든 패키지 · 타입 · 함수에
doc comment 가 붙어 있고, 그 내용이 「무엇을 한다」가 아니라 왜 이 형태인가 ·
어떤 대안을 왜 기각했나 · 어떤 실측이 이것을 고치게 했나다.
실측 사례가 식별자와 함께 인용되는 자리가 20곳 이상이다 — vm-scratch-7 ·
zephyr-setup-8 · colima-enode-1 · third-run-1 · reject-3 · rewind-1.
internal/store/schema.sql(144줄)은 스키마 파일이라기보다 주석이 절반 이상인
설계 문서에 가깝다 — 각 컬럼이 왜 있는지, CHECK 을 왜 안 거는지가 적혀 있다.
저장소 문서
README.md21,955바이트(483줄) — 슬라이스 표(S1~S10) · 패키지 배치 ·
불변식이 어디서 강제되는지를 코드 인용과 함께 적는다CLAUDE.md2,768바이트(72줄) — 두 개의 저장소 고유 규약(아래)
ADR 역추적성 — 이 저장소의 두드러진 강점
ADR-\d{3} 이 Go 소스에서 55개 서로 다른 번호로 인용된다(계측 확인).
ADR-INDEX.md 가 아는 62개 중 저장소 어디에도 안 나오는 것은 7개뿐이다.
| 안 나오는 ADR | 무엇 | 성격 |
|---|---|---|
ADR-001 |
Broker 안 둔다 | 부재의 결정 — 인용할 코드가 없다 |
ADR-003 |
점유는 Mediator 소유 | 내용은 구현돼 있고 번호만 안 붙었다 — internal/store/schema.sql 의 leases 주석과 internal/store/store.go |
ADR-006 |
테스트 두 종류 | |
ADR-034 |
하네스 팩 | system.md §5 가 「설계만」으로 분류한 것과 일치 |
ADR-035 |
부칠 수 없는 것만 요구 | system.md §5 가 「설계만」으로 분류한 것과 일치 |
ADR-039 |
완주만 판정 | 내용은 구현돼 있고 번호만 안 붙었다 — internal/store/claim.go:737-748 과 internal/api/api.go:294-297 이 ADR-004 · I3 를 인용한다 |
ADR-041 |
워크스페이스가 세 가지를 겸한다 |
없는 문서
OpenAPI / Swagger 없음(정본이 "OpenAPI 로 굳히지 않는다" 를 명시). godoc 외의
생성 문서 없음.
저장소 고유 규약과 그 집행 사이의 틈
CLAUDE.md 가 두 규약을 세운다. 둘 다 실제 코드와 틈이 관측된다. 판정이
아니라 관측으로 적는다.
규약 1 — 장식 문자를 안 쓴다
CLAUDE.md §1.2 는 「주석 · 문자열 · 로그 · 테스트 메시지 · 프롬프트 · 설정
파일 어디에도」 장식 문자를 안 넣는다고 적는다.
CI 가 집행하는 것은 U+2605 하나뿐이다 (현재 0건).
계측(이번 스캔에서 직접 재었다): U+2717 이 14줄, U+2713 이 2줄, 합 16줄.
그중 주석이 9줄이고, 주석이 아니라 실제 출력 문자열인 것이 7줄이다.
주석 9줄 — 「기각한 대안」을 표시하는 관행에 쓰인다. 규약 문면상으로는 이것도
대상이다.
internal/enode/changed.go:24, 26, 28
internal/enode/diff.go:21
internal/enode/hook.go:21
internal/enode/workspace.go:109
internal/schema/schema.go:9, 10
cmd/enode/hook.go:14
실제 출력 문자열 7줄 — 사람이 읽는 곳으로 나간다.
cmd/enodectl/main.go:71 fmt.Fprintf(os.Stderr, "✗ %v\n", err)
cmd/enodectl/main.go:258 fmt.Fprintln(os.Stderr, "✗ did not come up. tail of the log:")
cmd/runctl/main.go:388 mark = "✗ " (fmt.Printf 로 나간다)
cmd/iapadapter/comment.go:103 mark = "✗" (이슈 코멘트 판정 표시)
cmd/iapadapter/comment.go:105 mark = "✓"
cmd/iapadapter/comment.go:137 sch = "✓"
cmd/iapadapter/comment.go:139 sch = "✗"
규약 2 — 밖으로 나가는 것은 영어
CLAUDE.md §2 는 밖으로 나가는 문자열(에러 · 로그 · CLI 출력 · 테스트 이름 ·
픽스처 · 에이전트 프롬프트)을 영어로 쓴다고 적는다. 기준을 「코드냐」가 아니라
**「밖으로 나가느냐」**로 세운 이유까지 적혀 있다 — 제품이 실행 중에 자기 언어를
에이전트에 재주입하는 되먹임을 끊는다.
계측: cmd/iapadapter 는 It's a Plan 이슈 코멘트와 result 본문으로 나가는
문자열 20곳 이상이 한국어다.
main.go:156,163,208,222,238,245,250,332,358,385,396,450,458,459,467
comment.go:23,28,36,43-46,55,107
예: comment.go:107 의
"\n\n…(잘렸습니다. 전문은 봉인된 Record 에 있습니다)".
이 부품이 §2.3 이 말한 「밖으로 나가느냐」 기준의 경계선에 서 있다 — 읽는
쪽이 하네스가 아니라 사람이다. 규약이 이 경우를 어떻게 판정하는지는 이 문서가
결정하지 않는다.
기술 부채 — 통상적 신호는 0건
계측 확인. 흔히 찾는 신호가 하나도 없다.
| 신호 | 계측 |
|---|---|
TODO · FIXME · XXX · HACK · WIP 주석 |
0건 (전 Go 파일) |
비테스트 코드의 panic( |
0건 |
| 하드코딩된 자격증명 · API 키 | 0건 (토큰은 설정 파일 · 환경변수 경유이고, internal/enode/env.go 화이트리스트가 ENODE_TOKEN 을 하네스로 안 넘긴다) |
| 순환 의존 | 0건 |
| 미사용 의존 | 0건 (직접 3개 모두 실사용) |
gofmt -l . |
무출력 |
go vet ./... |
무출력 |
go test ./... -count=1 |
DB 유무 양쪽 모두 전 패키지 ok. 실패 · 플레이크 0건 |
TODO 를 안 쓰는 대신 「자리만 파 둔 것」을 doc comment 로 표시하는 관행이 있다
(internal/store/seal.go:95 ByMediator · internal/enode/env.go:60
RunIdentity · :88 Transparent{}).
기술 부채 — 실제로 있는 것 (구조적)
1. 계측 공백이 위험한 자리와 겹친다
위 「실제 테스트 공백」 참조. 요약: cmd/ 넷이 0% 이고
internal/enode/claim.go 가 24.8% 인데, 그 둘이 부팅 · 수명 · 임대 · 실행이라는
가장 되돌리기 어려운 경로다.
2. 함수 크기
internal/contract/contract.go:954 func (c Contract) Validate() error —
612줄. 계약 문법 전체의 단일 검증 함수다. 역할 · 간선 · DAG · 스키마 경계 ·
단계 종류 · 예약 이름 · dispatch 목적지 · ask 형태를 전부 여기서 본다. expands
로 자란 계약의 재검증 지점이기도 하다(expand.go:212 · :224).
30줄 넘는 함수 상위: applyExpands(273) · cmd/runctl/main.go run(250) ·
Worker.execute(222) · buildPrompt(210) · Verify(194) ·
cmd/mediator/setup.go runSetup(185) · RenewLeases(182) ·
cmd/enode/main.go main(173).
파일 크기: internal/contract/contract.go 1,724줄 · internal/store/claim.go
938줄 · internal/enode/claim.go 873줄 · internal/api/api.go 830줄. 테스트
파일 internal/api/api_test.go 는 3,342줄 단일 파일에 78개 테스트.
3. 중복
| 무엇 | 어디 | 성격 |
|---|---|---|
func nonce() string |
internal/api/api.go:826 · internal/store/acquire.go:243 |
본문이 완전히 동일(rand.Read(16) → hex.EncodeToString). 둘 다 ADR-010 허가 아티팩트의 nonce 를 만든다 |
func itoa(int) string |
internal/enode/harness.go:145 · internal/store/seal.go:228 |
store 쪽은 음수 처리가 없다(양수 seq 전용) |
byStep / ByStep |
internal/store/expand.go:350(비공개) · internal/store/seal.go:100(공개) |
같은 패키지 안에서 같은 본문("step:" + id)을 두 벌로 갖는다. seal.go:98 주석은 "아직 부르는 곳이 없다" 라고 적지만 seal_manifest_test.go:67-68 이 부르고, 실사용 호출 6곳은 전부 소문자 쪽이다 |
4. 마이그레이션 · 운영
Store.Migrate가schema.sql전문을 매 기동마다Exec한다. 버전
테이블도 롤백도 없다(store.go:71이 의도를 적는다).schema.sql이 이미
ALTER TABLE ... ADD COLUMN IF NOT EXISTS를 9번 쌓아 올린 상태이고,
그중 하나(steps.needs)는 백필UPDATE+SET NOT NULL을 매 기동 다시
돈다- 보관 · 정리 정책이 없다.
internal/record/record.go:193unseal의 주석이
운영 함의를 스스로 적는다 — "봉인은 삭제까지 막는다. … 디스크가 차면 사람이
지우지도 못한다." 이 함수는 지금 테스트 정리에만 쓰인다 sealExpired의 한 시간 창.internal/store/reap.go:106의 조회가
ended_at > now() - interval '1 hour'를 쓴다. Mediator 가 한 시간 넘게 죽어
있으면 그 사이 종료된 Run 은 이 경로로 봉인되지 않는다- 임시치가 셋 있다.
internal/config/config.go:57이 Lease 값 셋
(ttl_seconds3600 ·renew_seconds60 ·not_after_factor3)에 대해
"지금은 임시치이며S4에서 실측으로 고친다" 고 적는다 - claim 롱폴이 1초 티커 폴링이다.
internal/api/api.go:225주석: "MVP 는
짧은 주기로 DB 를 다시 본다.ADR-015가 적어둔LISTEN/NOTIFY는 …
최적화다. 지금은 넷이다." (:231, 최대 7,200초) - blob 을 직접 서빙한다.
internal/api/api.go:759getBlob— "ADR-018—
나중에 여기서 302 로 저장소를 가리킨다. 지금은 직접 서빙한다"
5. 트랜잭션 경계를 넘는 부수효과
internal/store/claim.go:339-343—ClaimStep이tx.Commit뒤에
stampStanding·stampRejections·stampRoleAttrs·stampLedger넷을
부른다. 각 함수가 실패를 삼키고 조용히 돌아온다(주석이 의도라고 적는다 —
"실패해도 단계를 막지 않는다").redeliver(claim.go:544-547)도 같은 넷을
부르는데, 두 경로가 같은 프롬프트를 만들어야 한다는 요구를 코드 중복으로
지킨다internal/store/acquire.godoAcquire는s.Records.WriteBlob을 트랜잭션
안에서 부른다 — 파일시스템 쓰기가 롤백되지 않는다internal/store/store.go:299—CreateRun이tx.Commit전에
s.Records.Open(runID)를 부른다(주석이 순서 이유를 적는다). 커밋이 실패하면
디렉터리가 남는다internal/store/ask.go:102PushAsks가go func()로 웹훅을 쏘고 결과를
기다리지 않는다 — 프로세스가 즉시 죽으면 유실된다(설계상 허용: 인박스가 정본)
6. 무시된 오류
비테스트 코드에서 _ = 로 오류를 버리는 지점 39곳. 대부분
defer Close() / Rollback 이지만, 판단이 섞인 것 넷이 있다.
| 위치 | 무엇 | 함의 |
|---|---|---|
internal/api/api.go:770 |
io.Copy |
blob 스트리밍 중 실패가 로그에도 안 남는다 |
internal/api/api.go:828 |
rand.Read |
실패하면 nonce 가 전부 0바이트가 된다 |
internal/store/acquire.go:245 |
rand.Read |
위와 동일 |
cmd/iapadapter/main.go:395,457,466 |
이슈 코멘트 전송 | 실패를 버린다 |
또 internal/store/reap.go:81 은 sealExpired 오류를 로그만 남기고 Reap 은
성공으로 돌아온다.
7. 죽은 코드 · 자리만 판 것
internal/store/seal.go:95ByMediator = "mediator"— 주석이 "아직 안 쓴다"
라고 적고 실제 참조 0건internal/enode/env.go:60RunIdentity— "지금은 아무도 안 본다"
(R2요청자 신원용 자리)internal/enode/env.go:88Transparent{}— 아무것도 주입 안 하는
Credentials구현. 의도적으로 nil 대신 타입을 둔 것을 주석이 적는다internal/store/claim.go:836_ = i(SettleIfDone의 재시도 소진 표시
루프.reap.go:246에도 같은 형태),internal/store/acquire.go:120
_ = taken,internal/enode/detect.go:64_ = ver— 셋 다 이유 주석이
붙어 있다R7의 광고 속성sandbox— Go 코드 전체에서 문자열sandbox가 0건.
Detect()가 광고하는 것은os·host_arch·harness·ws·repo·
arch·board·tag+ 사람이 붙인 라벨이다. 관측이며 판정이 아니다
(architecture.md관측 2)
문서 드리프트 — 관측
판정이 아니라 관측이다.
README.md§배치 가 나열하는 실행파일은cmd/mediator·cmd/enode·
cmd/runctl셋("셋이 다 있다")이다. 저장소에는cmd/enodectl과
cmd/iapadapter가 더 있다README.md§배치 에서internal/enode가 두 줄에 걸쳐 두 번 나온다system.md§5 는 "runctlasks/answer·show로 질문의 내용을 함께
보여주고" 라고 적는다.cmd/runctl의 하위명령 목록(main.go:124-310·
usage():402)에show가 없다.ledger하위명령도 없다- 표면 개수를 말하는 문장 셋이 서로 다른 수를 든다(12 / 12→13 / 13) —
api-documentation.md마지막 절 참조
이번 스캔이 환경에 남긴 것
scripts/testdb.sh 로 도커 컨테이너 enode-test-pg 를 만들어 커버리지를
재측정한 뒤 docker stop 했다. 컨테이너는 중지 상태로 남아 있고
docker rm enode-test-pg 로 완전히 지울 수 있다. 저장소 파일은 하나도 고치지
않았다.