v1.4.0 — 챕터가 읽을 만해지고, 점검이 자동으로 돈다
v1.1.0에서 챕터 읽기가 생겼을 때, 본문은 마크다운 원문 그대로 $PAGER로 넘어갔다. #과 **와 |가 눈에 그대로 밟혔다. 이번 릴리스는 그걸 렌더링하고, 그동안 사람 손에만 맡겨 뒀던 점검 일부를 기계에 넘긴다.
새로 생긴 것 — 터미널 마크다운 렌더러
./guide → 챕터 읽기로 연 본문이 이제 터미널용으로 조판되어 나온다. 표준 라이브러리만 쓰는 scripts/markdown_render.py이며, 외부 렌더러를 부르지 않는다.
- 제목·문단·구분선과 HTML 주석(벤더 마커) 처리
- 펜스 코드 블록을 상자로 감싸고, 그 안에서는 마크업을 해석하지 않는다 — 코드 안의
*가 강조로 먹히던 문제가 사라진다 - 목록·체크박스·인용문에 행잉 인덴트 — 두 번째 줄부터 첫 줄의 글머리 위치에 맞춰 들어간다
- 파이프 표를 열 너비에 맞춰 정렬하고, 넘치는 칸은 줄바꿈한다. 이 학습서는 DBMS 3종을 표로 비교하는 문서라 표가 많다
- 깊게 중첩된 목록·인용문, 언어 태그가 긴 펜스 헤더에서 폭이 넘치던 것을 고쳤다
색은 페이저가 받아 줄 때만 쓴다. less는 -R 없이는 ANSI 이스케이프를 그대로 찍어 버리므로, 페이저를 판별해 필요하면 -R을 붙인다. bat·delta는 목록에서 뺐다 — 그건 페이저가 아니라 포매터라, 우리가 조판한 결과를 한 번 더 조판한다.
CI가 생겼다
.github/workflows/tests.yml 하나. 테스트 스위트만 돌린다.
docs/release-policy.md의 「릴리스 전 점검」 10개 항목 중 자동으로 막아 줄 수 있는 것만 여기서 처리하고, 나머지(벤더 브랜치 재생성, 인스톨러 실검증 등)는 여전히 사람 몫이다. ./shoot doctor는 일부러 넣지 않았다 — docker와 DB 클라이언트 유무에 따라 결과가 갈리는데, 점검 목록이 doctor에 기대했던 「스테이지 정의 파싱」은 이미 ShippedStagesTest가 검증한다.
첫 실행이 곧바로 하나를 잡았다. macOS 러너에는 docker가 없는데, ClientCheckSymmetryTest가 머신의 docker를 읽고 있었다. 로컬에서 몇 달간 초록이던 테스트가 CI가 도는 첫날 빨개졌다 — 환경 차이를 가정하지 않은 테스트는 그 환경을 만나기 전까지 아무것도 증명하지 않는다.
scripts/check_content.py가 점검 목록의 기계로 판정 가능한 절반을 맡는다 — 상대 링크가 실제로 풀리는지, 티어·부록 문서가 README.md에서 빠지지 않았는지, 모든 챕터가 네 절 구조를 지키는지, 문제은행이 스키마에 맞는지. 링크 검사는 코드 펜스와 인라인 코드를 건너뛴다(문서가 자기 문법을 설명하는 자리를 오탐하지 않기 위해).
scripts/generate-branch.sh도 이제 실제로 돌려서 검증한다(tests/test_generate_branch.py) — 임시 저장소를 만들어 진짜 스크립트를 실행한다. v1.1.0에서 "브랜치를 실제로 잘라 돌려 봐야만 드러난다"고 적었던 종류의 결함을 이제 스위트가 잡는다.
install.sh — 커스텀 설치 경로를 기억한다
v1.2.0에서 인스톨러가 생긴 뒤 남아 있던 함정을 닫는다.
XDG_DATA_HOME으로 다른 경로에 설치한 사람이 다음 실행에서 그 값을 빠뜨리면, 스크립트는 지난 설치본을 찾지 못해 기본 경로에 두 번째 설치본을 만들고 링크를 그쪽으로 옮겼다. 원래 설치본과 학습 기록은 고아가 됐고, --purge는 더 나빴다 — 엉뚱한 트리를 지우고 진짜는 남겼다.
계약은 한 문장이다. 주면 그 값을 따르고, 주지 않으면 지난 위치를 기억한다.
- 클론에 성공한 순간 그 경로가
${XDG_STATE_HOME:-~/.local/state}/dba-guide/install-path에 기록된다. - 기록하는 것은 이번 실행이 직접 내려받은 트리뿐이다. 이미 있던 디렉터리를 지정한 경우에는 기록하지 않고, 그 사실을 화면에 알린다. 우리가 만들지 않은 트리에 소유권을 주장하면 한 번의 지정이 영구 조준점이 되어, 나중에 맨손으로 친
--purge가 엉뚱한 곳을 지운다. - 명시한
XDG_DATA_HOME이 기록을 이긴다. 그러지 않으면 설치를 옮길 방법이--purge(= 백업 없는 학습 기록 삭제)밖에 남지 않는다. --purge는 설치 경로가 심볼릭 링크면 거부한다.rm -rf는 링크만 지우고 트리를 남긴 채 "삭제했습니다"를 찍기 때문이다.
v1.3.0 이전에 커스텀 경로로 설치했다면 기록이 없다. 그 설치본은 이번 실행이 만든 것이 아니므로 기록하지 않으니, XDG_DATA_HOME을 업데이트·제거에 계속 함께 준다(v1.3.0과 같다). README.md에 적어 뒀다.
학습 점검
03-advanced/06-automation-and-iac 은행에 문항을 더해 --dbms 필터가 실제로 걸리게 했다(216 → 225문항). 단답 채점이 사람들이 실제로 치는 표기를 받아들이도록 다섯 문항의 허용 답안을 넓혔다.
벤더 브랜치
postgresql/mysql/oracle 세 브랜치를 이 릴리스 시점의 main에서 재생성해 push했다. 세 브랜치 모두 Ran 792 tests … OK (skipped=3), 챕터 마커 잔여 0, install.sh는 main과 바이트 동일.
검증에 대해
이 릴리스의 인스톨러 변경은 적대적 코드 리뷰 6라운드를 거쳤다. 그 과정에서 배운 것을 남긴다 — 처음 세 라운드는 매번 리뷰에 대한 대응 자체가 그 시점 최악의 결함을 만들었다.
원인은 하나였다. 소유권의 대리 지표를 다른 대리 지표로 바꿨을 뿐, 그 지표가 현실에서 어떤 상태를 갖는지 열거하지 않았다. 런처 링크는 in-place 설치에서 기여자의 작업 클론을 가리키고, "HEAD가 detached면 우리 것"이라는 판정은 서브모듈·워크트리·태그 확인 중인 클론이 전부 통과하며, 정작 릴리스 직후의 우리 설치본은 브랜치 위에 남는다. 답은 추론을 더하는 것이 아니라 아는 범위로 되돌리는 것이었다.
테스트에 대해서도 같은 것을 배웠다. 통과하는 테스트 수는 커버리지가 아니다 — 링크의 모양만 검사하고 실행하지 않았고, cwd를 숨은 입력으로 쓰는 함수를 언제나 저장소 루트에서만 돌렸고, 픽스처가 쉬운 분기만 타게 만들어 실제 설치가 지나는 경로를 통째로 비껴갔다. 지금은 각 불변식을 지우면 지정된 테스트가 실패하는 것까지 확인했다.
알려진 한계
발견되지 않은 버그가 아니라 알고 감수하는 경계다.
인스톨러
XDG_DATA_HOME을 자기dba-guide클론의 부모로 직접 지정하면 그 클론이 fetch·detach 된다.--purge의 삭제 가드도is_our_install(저장소 루트 +scripts/guide.py)뿐이라 기여자의 클론을 통과시킨다. 소유권은 git 상태에서 추론할 수 없다는 것이 이번 릴리스의 결론이고, 그래서 막는 대신 적어 둔다.- 설치 경로에
origin원격이 없는 저장소가 있으면 영어 git 오류로 죽는다. --purge는 파이프로 실행할 수 없다(확인에 tty가 필요하다). PATH 등록은 자동으로 하지 않는다.- Windows 네이티브 미지원. Homebrew·PyPI·컨테이너 이미지도 없다.
렌더러
- 표준 라이브러리만 쓰는 조판기다. 중첩 표, 각주, 정의 목록 같은 확장 문법은 다루지 않는다.
- 색은 페이저가 ANSI를 받아 줄 때만 켜진다. 판별에 실패하면 색 없이 나온다 — 읽기에는 지장이 없다.
판정 (./shoot)
- MySQL: 플레이어에게
SYSTEM_VARIABLES_ADMIN이 있어 엔진과 같은 방법으로 자기 명령을 로그에서 뺄 수 있다. 로그를 읽고 비우는 사이 수 ms의 유실 창이 있고, 로그 테이블에DELETE가 막혀 있어 고칠 수 없다. - PostgreSQL: 파싱 오류가 감시에 남지 않는다(실측 — 없는 테이블·권한 오류는 잡히고
KILL 999999는 놓친다). pid를 적지 않는pg_terminate_backend쓸기는kill_precision이 못 본다.
커버리지 공백
- 스테이지 14개 중 MySQL 13 / PostgreSQL 1. Oracle 스테이지는 없다.
- 문항 벤더 표기가 전부
neutral인 은행이 하나 남아 있다(01-beginner/01).
운영
- CI는 테스트만 돌린다. 벤더 브랜치 재생성, 릴리스 발행, 인스톨러 실검증은 여전히 사람이 손으로 한다.
- 인스톨러는 최신 태그를 설치하므로, 이 릴리스를 발행해야 비로소 그 내용이 배포된다.
요약
| v1.3.0 | v1.4.0 | |
|---|---|---|
| 챕터 | 31 | 31 |
| 문제은행 / 문항 | 23 / 216 | 23 / 225 |
| 스테이지 | 14 | 14 |
| 챕터 읽기 | 마크다운 원문 | 터미널 렌더링 |
| CI | 없음 | 테스트 스위트 (macOS·Linux, Python 3.9·3.13) |
| 릴리스 점검 자동화 | 없음 | check_content.py (링크·구조·은행) |
| 커스텀 설치 경로 | 매번 지정 | 기억한다 (직접 내려받은 것만) |
| 테스트 | 592 | 792 |
커밋 46개. 전체 변경 이력: v1.3.0...v1.4.0
호환성: 더해지고 고쳐졌다. 제거되거나 의미가 바뀐 CLI 인자, 스키마 변경, 진행·결과 기록 형식 변경, 챕터 경로 변경 모두 없다. install.sh에 상태 파일이 하나 생기지만(~/.local/state/dba-guide/install-path) 없어도 v1.3.0과 똑같이 동작한다.