---
task_id: task-3027
scope: task
team: dev8
owner: 라(Ra)
type: cron-execution
status: success_with_known_benign_exit1
created_at: "2026-08-26 12:15 KST"
---

# task-3027 — update-system-spec.py 정기 실행 (4회차)

## S (상황)

`python3 /home/jay/workspace/scripts/update-system-spec.py` 정기 실행 요청.
동일 크론은 6시간 주기로 돌며, 직전 3회(task-3015 / task-3020 / task-3022)에서
"exit code 1 + `[cron] 데이터 변경` 로그"가 **거짓 양성**임이 이미 규명되어 있다.

## C (복잡성)

두 가지가 이번 회차에서 직전 3회와 달랐다.

1. **실제 변경이 처음으로 발생했다.** 직전 3회의 diff는 `task_stats` 3~4줄뿐이었으나,
   이번엔 `services` 섹션이 실제로 바뀌었다(17개 → 15개).
2. **`task-3023` 이 이미 점유되어 있었다.** 다음 순번으로 짐작해 착수했다면
   09:17에 타 팀으로 위임된 작업의 산출물을 덮어쓸 뻔했다.

## Q (질문)

- exit code 1 이 이번에도 알려진 거짓 양성인가, 아니면 새로운 실패인가?
- `services` 변경은 진짜인가, 수집 실패로 인한 유실인가?
- cron 블록이 이번에도 보존되었는가?

## A (답변)

**exit 1 은 4회 연속 동일한 거짓 양성이며, 문서 갱신 자체는 성공했다.**
`services` 변경은 실제이며 systemd 교차 검증으로 확증했다. cron 블록은 무변경이다.

---

## 1. 실행 결과

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

`cron` 만 수집 실패, 나머지 5개 섹션은 정상 수집. exit 1 의 원인은 이 한 섹션뿐이다.

## 2. 실제 변경 내역 (spec diff = 14줄)

### 2-1. services: 17개 → 15개

| 구분 | 서비스 | systemd 실측 |
|------|--------|--------------|
| 추가 | `insuro-preview.service` | `active` |
| 삭제 | `at-spi-dbus-bus.service` | `inactive` |
| 삭제 | `dbus.service` | `inactive` |
| 삭제 | `gpg-agent.service` | `inactive` |

`systemctl --user list-units --state=running` 실측 **15개** = 문서 기재값 15개 일치.
삭제된 3개는 데스크톱 세션 의존 서비스(전부 실제 inactive)이고,
`insuro-preview.service` 는 실제 기동 중인 신규 서비스다.
→ **수집 실패로 인한 유실이 아니라 실제 상태 변화**로 판정.

### 2-2. task_stats

| 항목 | 이전 | 이후 |
|------|------|------|
| 총 작업 수 | 2265 | 2270 |
| 완료된 작업 | 2202 | 2203 |
| 완료율 | 97.2% | 97.0% |
| 평균 소요시간 | 1시간 10분 13초 | 1시간 10분 11초 |

## 3. cron 블록 보존 검증 (핵심)

`detect_changes()` 는 수집 실패(`new = None`)를 캐시의 `old` 와 비교해 무조건
"변경"으로 계산하지만, 문서 갱신 루프는 `if section not in new_state: continue`
로 건너뛴다. 따라서 **로그만 찍히고 문서는 그대로**여야 한다. 실측으로 확인했다.

| 검증 항목 | 결과 |
|-----------|------|
| 마커 구간 md5 (before) | `af7090faa1da20f713b9f6e31ae7eb8c` |
| 마커 구간 md5 (after) | `af7090faa1da20f713b9f6e31ae7eb8c` |
| `diff` 결과 | **0줄 (IDENTICAL)** |
| 블록 내 `created_at` | `2026-04-16 11:16:10` (동결 유지) |

→ cron 블록은 손대지 않았다. 데이터 손실 없음. **Critical 7 아님.**

> 참고: 메모리에 기록된 직전 md5 `fe2c287b…` 와 값이 다르나, 이는 md5 계산 구간
> 정의(마커 포함/제외) 차이에서 오는 표기 차이다. 판정 근거는 절대값이 아니라
> **동일 실행 내 before↔after 대조**이며, 그 결과는 diff 0줄이다.

## 4. changelog 기록

`memory/specs/anu-system-spec-changelog.md` 최상단(최신순)에 자동 기록됨:

```
## [2026-08-26 12:16] 변경 내역
- [cron] `cron` 데이터 변경                                    ← 거짓 양성
- [services] `running_services` 추가: `insuro-preview.service`
- [services] `running_services` 삭제: `at-spi-dbus-bus.service`
- [services] `running_services` 삭제: `dbus.service`
- [services] `running_services` 삭제: `gpg-agent.service`
- [task_stats] `task_stats` 데이터 변경
```

`memory/CHANGELOG.md` 는 이 스크립트의 대상이 아니며 **무변경**(diff 0)이다.

---

## ★ 부수 발견 1 — 12:00 정기 백업 누락 (ANU 확인 필요)

`scripts/backup-spec.sh` 는 `update-system-spec.py` 와 **별개 스케줄**로 돌며
spec 파일의 유일한 안전망이다. 디렉터리 mtime 실측:

```
2026-08-24_12  12:00:18      2026-08-25_12  12:00:18
2026-08-24_18  18:00:18      2026-08-25_18  18:00:23
2026-08-25_00  00:00:20      2026-08-26_00  00:00:15
2026-08-25_06  06:00:17      2026-08-26_06  06:00:17
2026-08-26_12  ← 부재
```

8회 연속 `HH:00:1x` 에 정확히 실행됐는데 **오늘 12:00 회차만 없다**(현재 12:18).
즉 이번 변경분은 정규 백업 없이 덮어써졌다.

- 사용자 `crontab -l` 에 `backup-spec` 항목 **없음** → cokacdir cron(타 키 소유)로 추정.
  `--cron-list` 는 key 스코프라 dev8 키로는 조회 불가 → **원인 확정 불가, ANU 확인 필요.**
- 완화 조치: 실행 전 스냅샷을 증거로 영구 보존했다(아래 표).
- **누락된 `2026-08-26_12` 백업을 임의 생성하지 않았다.** 사후 생성하면 변경 *이후*
  내용이 담겨 의미가 뒤집히고, 스케줄러 장애를 은폐하게 된다.

## ★ 부수 발견 2 — task-3023 ID 재사용 회피

`task-3022` 다음이라고 짐작해 `task-3023` 으로 착수했으나, timer 가
`already_running (09:22:14)` 을 반환했다. 확인 결과 `memory/plans/tasks/task-3023.md`
가 09:17 생성된 **타 팀 위임 작업**이었다.

- `start` 호출은 `already_running` 을 반환하고 **기존 기록을 덮어쓰지 않았다** → 피해 0.
- plans / reports / events 3곳을 전수 조회해 3023~3026 점유 확인, **task-3027** 로 착수.
- 이는 260825에 기록된 동일 사고(ANU 의 task-3020 재사용)와 같은 유형이다.
  번호는 짐작하지 말고 **3개 디렉터리 전수 조회**로 확보해야 한다.

---

## 수정 파일별 검증 상태

| 파일 (절대경로) | 변경 | 검증 방법 | status |
|---|---|---|---|
| `/home/jay/workspace/memory/specs/anu-system-spec.md` | services 6줄·task_stats 8줄 (총 14줄) | before/after diff 전문 + systemd 실측 교차검증 + cron 블록 md5 동일성 | verified |
| `/home/jay/workspace/memory/specs/anu-system-spec-changelog.md` | 최신 항목 7줄 추가 | `head -25` 로 날짜·항목 육안 확인 | verified |
| `/home/jay/workspace/memory/CHANGELOG.md` | 없음 | `diff -q` 무변경 확인 | verified |
| `/home/jay/workspace/memory/reports/task-3027-evidence/anu-system-spec.PRE-RUN.md` | 신규(증거) | md5 `4da8f80e…` = 실행 전 원본 일치 | verified |
| `/home/jay/workspace/memory/reports/task-3027-evidence/spec.diff.txt` | 신규(증거) | diff 전문 보존 | verified |
| `/home/jay/workspace/memory/reports/task-3027-evidence/run.stdout.txt` | 신규(증거) | 실행 로그 원문 | verified |
| `/home/jay/workspace/memory/reports/task-3027-evidence/run.stderr.txt` | 신규(증거) | 실패 사유 원문 | verified |

## 판정

| 항목 | 결과 |
|------|------|
| 스펙 문서 갱신 | **성공** |
| changelog 기록 | **성공** |
| exit code | 1 (알려진 거짓 양성, 4회 연속) |
| 데이터 손실 | **없음** |
| Critical 7 해당 | **아님** → 회장님 실패 알림 대상 아님 |
| ANU 확인 요청 | 12:00 백업 누락 1건 |

## 근본 해소 제안 (미착수 — 승인 필요)

exit 1 의 반복은 하루 4회 누적된다. 두 갈래 중 택일이 필요하다.

1. 크론 실행 환경에 **ANU 소유** `ANU_CHAT` / `ANU_KEY` 주입
2. `detect_changes()` 가 수집 실패 섹션을 변경으로 계산하지 않도록 수정
   (`new is None` 이면 skip)

★ **dev8 등 팀 봇 키로 대체 수집은 금지.** `--cron-list` 는 key 소유자 스코프라
부분집합으로 덮어써져 문서가 퇴행한다. 현재의 "실패 → 기존 블록 보존"이 더 안전하다.
