---
scope: task
task_id: task-3020
title: update-system-spec.py 정기 자동 실행 (시스템 스펙 문서 갱신)
owner: 라(Ra) / 개발8팀
status: verified
date: 2026-08-26
---

# task-3020 — 시스템 스펙 자동 업데이트 정기 실행

## S (상황)

스케줄 크론이 `python3 /home/jay/workspace/scripts/update-system-spec.py` 실행을
지시했다. 지시문은 3가지다: (1) 스펙 문서 자동 갱신, (2) 변경 사항이 있으면
changelog 기록, (3) 실패 시 제이회장님께 알림.

직전 동일 작업은 **task-3015**(2026-08-25)이며, 그 실행에서 changelog 의
`[cron] 데이터 변경` 이 **수집 실패의 거짓 양성**임이 규명되었다. 이번 실행은
그 결론을 전제로 **문서 실제 diff 로 교차검증**하는 방식을 적용했다.

## C (문제)

실행 결과 **exit code = 1** (부분 실패). 6개 섹션 중 `cron` 수집만 실패.

```
[FAIL] cron: ANU_CHAT 환경변수가 설정되지 않았습니다.
  [OK] skills
  [OK] services
  [OK] projects
  [OK] scripts
  [OK] task_stats
[update-system-spec] 변경 감지: ['cron', 'task_stats']
[update-system-spec] 업데이트 완료 / 변경 로그 기록 완료
```

원인은 신규 결함이 아니라 기존 식별된 환경변수 갭이다 —
`scripts/update-system-spec.py` 의 `collect_cron()` 이
`cokacdir --cron-list --chat $ANU_CHAT --key $ANU_KEY` 를 호출하는데
크론 실행 환경에 `ANU_CHAT` / `ANU_KEY` 가 주입되지 않는다.

## Q (검증 — changelog 를 믿지 않고 실제 diff 대조)

changelog 는 이번에도 2줄을 찍었다:

```
## [2026-08-26 00:16] 변경 내역
- [cron] `cron` 데이터 변경
- [task_stats] `task_stats` 데이터 변경
```

그러나 **문서 실제 변경분은 `task_stats` 한 섹션뿐**이다.

실행 전 스냅샷(`/tmp/spec_before_3020.md`) 대비 전체 diff:

```
md5 before : 98fcbc59010dba5be991c0fd4342bf4e
md5 after  : 5d278b6bcb1a3fd4aeb5ec53ed8f5f0b

1167,1170c1167,1170
< | 총 작업 수 | 2257 |          > | 총 작업 수 | 2263 |
< | 완료된 작업 | 2195 |         > | 완료된 작업 | 2200 |
< | 완료율 | 97.3% |             > | 완료율 | 97.2% |
< | 평균 소요시간 | 1시간 10분 19초 | > | 평균 소요시간 | 1시간 10분 16초 |
```

**diff 는 이 4줄이 전부다.** `AUTO:cron` 블록(601~658행)은 단 한 글자도
바뀌지 않았고, 여전히 `created_at: 2026-04-16 11:16:10` 기준으로 동결돼 있다.

즉 changelog 의 `[cron] 데이터 변경` 은 이번에도 **거짓 양성**이다.
`detect_changes()` 가 수집 실패 시 `new = None` vs 캐시의 non-None `old` 를
`old != new` 로 판정해 항목을 만들지만, 정작 문서 갱신 루프는
`if section not in new_state: continue` 로 건너뛰기 때문이다.

## A (조치 / 판정)

| 지시 항목 | 결과 |
|---|---|
| 스펙 문서 자동 갱신 | **완료** — `task_stats` 5개 섹션 반영, 문서 무결 |
| 변경 사항 changelog 기록 | **완료** (스크립트 자동) — 단 `[cron]` 줄은 거짓 양성 |
| 실패 시 알림 | **보고** — 아래 사유로 Critical 7 아님 |

### 알림 등급 판정 — Critical 7 아님

- 실패 섹션은 `cron` **1개**이며, 실패 시 동작은 **기존 블록 보존**이다.
  덮어쓰기·절삭·데이터 손실이 **없다**.
- 나머지 5개 섹션은 정상 수집·반영됐다.
- 증상이 최소 2026-04-16 이래 동일하게 반복된 **기존 결함**이며 신규 사고가 아니다.
- 따라서 즉시 에스컬레이션 대상이 아니라 **정기 보고 항목**으로 분류한다.

### 수행하지 않은 것 (의도적)

- **팀 봇(dev8) 키로 대체 수집 금지 준수.** `--cron-list` 는 key 소유자 스코프라
  dev8 키로 채우면 ANU 전체 스케줄이 **부분집합으로 덮어써져 문서가 퇴행**한다.
  현재의 "수집 실패 → 기존 블록 보존" 이 더 안전하다.
- **스크립트 코드 수정 안 함.** 근본 해소는 코드 변경이 필요한데
  (a) 본 스케줄의 위임 범위가 "실행/기록/알림"이며,
  (b) 2026-08-25 자로 쓰기 동결이 걸려 있고,
  (c) dev8 규칙상 코드 작성은 GLM 팀원 위임 대상이다.
  → 별도 task 로 상신한다.
- **커밋/푸시 안 함.** 두 파일은 워킹트리 변경으로 남겨 뒀다
  (`memory/specs/anu-system-spec.md`, `anu-system-spec-changelog.md`).
  종래에도 이 자동 산출물은 타 작업의 사이드 이펙트로만 커밋돼 왔다.

## 권고 — 근본 해소 2갈래 (회장님 판단 필요)

1. **크론 환경에 ANU 소유 `ANU_CHAT` / `ANU_KEY` 주입**
   → cron 블록이 4개월 만에 실제 갱신된다. 단 키 노출면이 늘어난다.
2. **`detect_changes()` 가 수집 실패 섹션을 "변경"으로 계산하지 않도록 수정**
   → 문서는 그대로 동결되지만 changelog 의 거짓 양성이 사라지고
     exit code 가 정직해진다. 위험도 낮음.

**둘은 배타적이지 않다.** 다만 (2)를 먼저 하면 이후 (1)을 적용했을 때
"진짜 변경"이 로그에서 즉시 식별된다. (2) → (1) 순서를 권고한다.

## 수정 파일별 검증 상태

| 파일 | 변경 | 검증 상태 |
|---|---|---|
| `/home/jay/workspace/memory/specs/anu-system-spec.md` | task_stats 4줄 | verified (전체 diff 대조) |
| `/home/jay/workspace/memory/specs/anu-system-spec-changelog.md` | 신규 블록 1개 | verified (`[cron]` 줄은 거짓 양성으로 판정) |
| `/home/jay/workspace/scripts/update-system-spec.py` | 없음 | 미변경 (의도적) |
