- name
- a-living-doc-repeats-a-fact-and-updates-only-one-copy
- description
- Living 문서(STATUS·ROADMAP·인수인계)는 같은 사실을 산문·취소선·표에 여러 번 적는데, 갱신은 **산문만** 된다 — 표의 행이 가장 늦게 썩고, 그 행이 백로그를 이슈로 옮길 때 근거가 된다. 그리고 문서 이주·의존성 제거 과제에서는 **옮기기 전에 그 참조가 아직 살아 있는지부터 재라** — 실측하니 코드의 문서 인용 13개 중 8개가 이미 죽은 링크였다. 그리고 **이주는 다른 세션에 전파되지 않는다** — 옛 경로에 쓰는 것은 실패하지 않고 아무도 안 읽는 곳에 성공한다. 옛 자리에 경고를 남기고 며칠 지켜봐라. 트리거 - 문서 백로그를 이슈화, 문서를 다른 레포로 이주, "열려 있음"이라 적힌 항목 착수, 외부 의존성 제거, 옛 경로에 파일이 새로 생겼을 때.
- version
- 1.0.0
- task_types
- ["analysis","review","workflow"]
- triggers
- [{"pattern":"문서의 '미완 작업' 목록을 GitHub 이슈로 옮길 때"},{"pattern":"문서를 다른 레포/저장소로 이주시키며 살아있는 것과 죽은 것을 가를 때"},{"pattern":"문서가 '아직 local' '미실행' '열려 있음' 이라고 말하는 항목에 착수할 때"},{"pattern":"외부 의존성(레포 밖 문서·경로)을 제거하는 과제를 시작할 때"},{"pattern":"같은 사실이 한 문서 안 여러 절에 나올 때"},{"pattern":"문서를 이주시킨 뒤 옛 경로에 파일이 새로 생겼을 때"},{"pattern":"여러 세션이 동시에 도는 환경에서 저장 위치 규칙을 바꿀 때"}]
- category
- trap
# Living 문서는 같은 사실을 세 번 적고 한 번만 고친다
## Problem
2026-09-12, `~/Docs` 를 레포 안으로 흡수하며 "살아있는 todo 를 이슈로" 옮겼다.
`STATUS.md`(800줄, Master Status SoT)의 **미완 작업** 목록에서 R2 cutover 를
읽고 이슈를 열었다. 30분 뒤 실측으로 그 이슈를 닫아야 했다.
같은 파일 안에서 **같은 사실이 세 번** 나왔고, 서로 달랐다:
| 위치 | 형태 | 내용 |
|---|---|---|
| 113줄 | 산문 | ✅ **cutover 완료** (2026-08-18 실측: prod = `s3`) |
| 788줄 | 취소선 | ~~아직 `local`~~ → ✅ 완료 |
| **312줄** | **표의 행** | ⚠️ 코드 완성, **prod cutover 미실행** |
실측: `deploy/.env.prod:41` → `BSVIBE_PRODUCT_BUNDLE_BACKEND=s3`. **완료가 맞다.**
**산문 두 곳은 갱신됐고 표의 행만 4주째 낡아 있었다.** 그리고 백로그를 추출할 때
내가 고른 건 하필 그 표였다 — 표는 스캔하기 좋아서 목록 추출의 1순위가 된다.
> 사람은 문단을 고칠 때 그 문단만 본다. 표는 "데이터"로 느껴져서 산문 수정의
> 사정거리 밖에 있다. **가장 구조화된 표현이 가장 늦게 썩는다.**
### 같은 뿌리로 두 번 틀렸다
1. `BSVibe_Product_Bundle_R2_Cutover_Runbook.md`(08-03) 가 머리에 *"현재 상태:
프로덕션은 아직 `local`"* 이라고 적고 있었다 → **살아있는 열린 작업**으로 판단해
레포로 승격했다. 되돌렸다.
2. 그 런북을 근거로 이슈 #934 를 열었다. 실측으로 닫았다.
**둘 다 "문서가 자기에 대해 하는 말"을 근거로 썼다.** 런북은 *실행 전에* 쓰인
문서다 — 실행됐다는 사실이 그 문서에 되먹여질 이유가 구조적으로 없다.
## Rule
### 1. 문서 백로그를 이슈화하기 전에 그 문서의 자기 일관성부터 세라
```bash
# 같은 키워드가 그 문서 안에서 몇 번, 어떤 판정으로 나오는가
grep -n "R2\|BUNDLE_BACKEND" docs/STATUS.md
# → 113 완료 · 312 미실행 · 788 취소선 ⇒ 모순. 실측 전에는 아무것도 이슈화하지 마라
```
**항목 하나가 아니라 그 항목의 모든 등장을 세라.** 하나만 보면 그게 최신인지
가장 낡은 것인지 알 방법이 없다.
### 2. "열려 있음"의 출처가 실행 전 문서면 그건 상태가 아니라 계획이다
| 문서 종류 | 자기 상태 서술을 믿어도 되나 |
|---|---|
| 런북 · 계획 · 설계 브리프 | ❌ **실행 전에 쓰였다.** 실행됐다는 사실이 되돌아오지 않는다 |
| Living STATUS 의 **산문** | 🔶 갱신은 되지만 절마다 시차가 있다 |
| Living STATUS 의 **표** | ❌ 가장 늦게 갱신된다 |
| **prod 설정 / 코드 / DB** | ✅ 유일한 근거 |
### 3. 의존성 제거 과제는 "그 의존성이 아직 살아 있나"를 먼저 잰다
레포 밖 문서(`~/Docs/...`)를 인용하는 코드 주석을 전수로 열어봤다:
```bash
grep -rhoE '~/Docs/[A-Za-z0-9_./-]+\.md' --include="*.py" --include="*.md" . \
| sed 's|~/Docs/||' | sort -u \
| while read f; do [ -f ~/Docs/"$f" ] && echo "OK $f" || echo "BROKEN $f"; done
```
**13개 중 8개가 이미 죽은 링크였다** (archive 로 옮겨졌거나 파일 자체가 없음).
이 한 줄이 작업 범위를 바꿨다 — 죽은 8개는 이주 대상이 아니라 **표기 정정**
대상이었다. 재지 않았으면 없는 파일을 찾아다니거나, 죽은 문서를 정성껏 옮겼을 것이다.
> **의존성은 "있다/없다"가 아니라 "몇 %가 아직 닿나"다.** 제거 과제의 첫 측정은
> 목록이 아니라 **생존율**이다.
### 4. 옮긴 뒤에는 열 수 없는 가리킴을 남기지 마라
죽은 참조를 경로처럼 쓰면 계속 열리는 척한다. **열 수 없음이 표기에 보이게** 하라.
```python
# ❌ 열리는 척한다
Design source: ``~/Docs/BSVibe_Class_Architecture_Design_2026-05-30.md``
# ✅ 어디 있는지 말하되 경로인 척하지 않는다
Design source: ``internal-docs:BSVibe_Class_Architecture_Design_2026-05-30.md``
```
같은 함정이 다음 층에서 재발한다: "과거 인수인계는 Notion" 이라고만 쓰고 **URL 을
안 적으면** 그것도 열 수 없는 가리킴이다. 이주 PR 직후 그 결함을 그대로 만들었고
후속 PR 로 고쳐야 했다.
### 5. 저장 위치를 옮겨도 다른 세션은 모른다 — 옛 자리를 지켜라
이주 커밋을 push 한 **40분 뒤**, 이 전환을 모르는 다른 세션이 옛 경로에 인수인계를
새로 썼다. 원본이 레포로 갔다는 걸 몰라 **이어붙이려던 절만 고아로** 남았고, 내용은
그날 배포된 보안 수정(prod SHA 포함)이라 버리면 안 되는 것이었다.
> **위치 변경은 코드 변경과 달리 CI 가 안 잡는다.** 옛 경로에 쓰는 것은 실패하지
> 않는다 — 그냥 아무도 안 읽는 곳에 성공적으로 쓰인다.
옛 자리를 **지우고 끝내지 마라.** 세 가지를 남겨라:
1. **표지** — 옛 디렉터리의 `README` 에 새 위치 대조표. 단, 파일만 쓰고 가는
세션은 README 를 안 읽는다. 표지는 충분조건이 아니다
2. **경고** — *"여기 `<패턴>` 이 새로 생기면 누가 옛 경로로 쓴 것이다.
**지우기 전에 읽고** 새 자리로 옮겨라"*
3. **점검** — 이주 후 며칠은 옛 자리를 한 번씩 본다
```bash
# 옛 자리에 새로 생긴 것이 있나 (이주 커밋 이후 mtime)
ls -la ~/OldDocs/*.md 2>/dev/null
cd ~/OldDocs && git status --short # ?? 로 뜨면 이주 후에 쓰인 것이다
```
발견하면 **내용부터 읽어라.** 옛 경로에 있다는 것은 낡았다는 뜻이 아니라
**가장 새것일 수 있다** — 그 세션은 최신 상태를 알고 썼다.
## Checklist
- [ ] 이슈화 전: 그 항목이 문서 안에서 **몇 번** 나오는지 grep 했나
- [ ] 근거로 쓴 문서가 **실행 전에 쓰인 것**은 아닌가 (런북·계획·설계)
- [ ] 최종 판정을 **prod 설정·코드·DB** 로 확인했나
- [ ] 의존성 제거면 **생존율**을 먼저 쟀나 (닿는 참조 / 전체 참조)
- [ ] 옮긴 뒤 남긴 참조가 **열 수 있거나, 열 수 없음이 보이나**
- [ ] 모순을 발견했으면 **낡은 쪽도 고쳤나** (이슈만 닫고 문서를 두면 다음 사람이 또 걸린다)
- [ ] 이주라면 옛 자리에 **경고를 남기고** 며칠 지켜보나 (다른 세션은 전환을 모른다)
## Related
- `audit-findings-need-remeasurement-before-acting` — 감사 발견 12건 중 8건이 재측정에서 틀렸다. 이 스킬은 그 대상을 **문서의 자기 서술**로 넓힌다
- `a-dead-entity-can-be-the-subject-of-a-live-claim` — 역방향. 죽은 것이 살아있는 주장의 주어가 된다
- `recorded-deploy-baseline-is-not-the-commit-time` — 기록된 값과 실제 시점의 어긋남
GitHubで見る