# task-2723+3 — critical_gap zero-count REDESIGN: severity별 count 구조 파싱 (LOOP_BOUNDARY 후 구조적 재설계, 회장 승인)

## 회장 인가 (2026-06-03, LOOP_BOUNDARY → redesign 승인)
critical_gap zero-count 판단이 `_is_zero_count_context`/`_ZC_ZERO_EXPR` 영역에서 3회 진동:
- round-1: over-broad false-negative / round-2: word-boundary false-positive / round-3: **mixed-count false-negative**
→ LOOP_BOUNDARY. **추가 regex 한 줄 incremental patch 금지.** 라인 전체 suppress 휴리스틱을 폐기하고 **severity별 count pair 구조 파싱**으로 전환.

## worktree
- `/home/jay/workspace/.worktrees/task-2723-dev2` (branch `task/task-2723-dev2`, head `a2783b39`)에서 **이어서**. new head → non-force push.

## 핵심 redesign (라인 전체 suppress → severity-count 구조 파싱)
한 줄을 통째로 zero-count 로 suppress 하지 말고, **줄에서 severity별 (severity, count) 쌍을 파싱**하여 판정한다.

`_is_zero_count_context(line)` 재구현(아래 순서):
1. **STRONG_ISSUE_MARKER** 있으면 → `return False` (실제 finding 줄 — `[CRITICAL]`/`[HIGH]`/`![critical]`/`![high]`/`severity:critical|high`).
2. **VULN_NEGATION_DENYLIST** 있으면 → `return False` (실제 취약점 부정/제로 — 인증/권한 검증/암호화/패치/수정/조치/해결 없음, secure_mode=0/timeout=0/port=0).
3. **severity-count 파싱** `counts = parse_severity_counts(line)`:
   - severity 토큰(CRITICAL/HIGH/심각/블로커)에 결합된 숫자를 추출. 예:
     - `"CRITICAL: 0, HIGH: 1"` → `[0, 1]`
     - `"CRITICAL 0개, HIGH 2개"` → `[0, 2]`
     - `"HIGH/CRITICAL 0건"` → `[0]`(또는 `[0,0]` — severity group 에 단일 0 적용)
     - `"fresh unresolved HIGH/CRITICAL = 0"` → `[0]`
     - `"CRITICAL=0"` → `[0]`
   - `if counts:` → **`return all(c == 0 for c in counts)`** (모든 severity count 0 → zero-count(suppress); 하나라도 >0 → not zero-count(탐지 유지)).
4. **숫자 없는 부재형**: `if COUNT_ANCHOR.search(line) and ABSENCE_EXPR.search(line): return True`
   - COUNT_ANCHOR = HIGH/CRITICAL/심각/블로커/이슈/issue/finding(s)/취약점/건수/count/미해결/unresolved/신규 HIGH·CRITICAL
   - ABSENCE_EXPR = `없음|없습니다|없다` (severity/이슈 anchor 동반 시 zero 의미). 예: `"신규 HIGH 없음"`, `"이슈없음"`, `"이슈없다"` → True(PASS).
   - "총0건": severity 미지정 총계 0 → 숫자 0 + 건/개 단위 + severity>0 부재 → zero-count 처리(예: `(?<!\d)0\s*(?:건|개)` 가 줄의 유일 카운트이고 >0 카운트 없음 → True). 단 anchor 없는 단독은 후보 자체가 아님(critical 토큰 필요).
5. `return False`.

★ **핵심 차이**: round-1~3 은 "줄에 zero 표현 있으면 통째 suppress". redesign 은 "줄의 모든 severity count 가 0일 때만 suppress, 하나라도 >0이면 그 줄은 실제 이슈". → `"CRITICAL: 0, HIGH: 1"` 처럼 mixed-count 에서 HIGH 1 을 정확히 탐지(FAIL).

## 불변 (변경 금지)
- `verify()` public interface + return schema `{"status","details"}` 불변.
- 기존 `_detect_critical_lines` 후보 탐지(CRITICAL 토큰 기준)·화이트리스트·메타라벨·RESOLVED 로직 불변. zero-count 판정 함수(`_is_zero_count_context` 본문)만 구조 파싱으로 교체.
- strong issue marker / vuln denylist 미억제 원칙 유지.

## 허용 파일 (expected_files 2개 — 그 외 수정 금지)
1. `teams/shared/verifiers/critical_gap.py` ← `_is_zero_count_context` 구조 파싱 재구현 (+ `parse_severity_counts` 헬퍼 추가 가능). 기존 regex 상수는 헬퍼 내부 재사용/정리 가능하나 외부 인터페이스 불변.
2. `tests/regression/test_critical_gap_false_positive_2506.py` ← mixed-count 회귀 추가 + 기존 유지.

## 필수 regression (회장 명시)
PASS:
1. HIGH/CRITICAL 0건  2. CRITICAL=0  3. fresh unresolved HIGH/CRITICAL = 0  4. 신규 HIGH 없음 / 신규 CRITICAL 없음
5. 총0건  6. 이슈없음 / 이슈없다
FAIL:
1. **CRITICAL: 0, HIGH: 1** (★ mixed-count — HIGH 1 탐지)
2. **CRITICAL 0개, HIGH 2개** (★ mixed-count — HIGH 2 탐지)
3. [CRITICAL] 인증 없음  4. [CRITICAL] 권한 검증 없음  5. [CRITICAL] 암호화 없음
6. [HIGH] secure_mode=0  7. [HIGH] timeout=0  8. [CRITICAL] port=0  9. 신규 버그, 패치 없음([CRITICAL] 문맥)
10. 기존 unresolved HIGH/CRITICAL 탐지력(기존 fp/tp/zc 전부 유지)

## 금지 (회장 verbatim)
- expected_files 2개 밖 수정 금지 · **verifier public interface/schema 변경 금지** · finish-task.sh / dispatch runtime / pickup / systemd / activation / systemctl / real wake / credential 확장 / Work 착수 / merge / force push·rebase·admin override 금지.

## 검증 조건
1. redesign regression 전부 의도대로 PASS (PASS 케이스 + mixed-count FAIL 2 + 기존 FAIL + 탐지력 보존).
2. `git diff --name-only origin/main` = expected_files 2파일 내부. 3. forbidden 0. 4. ANU key full literal(`c119085addb0f8b7`) 0. 5. verify interface/schema 불변.
- smoke: `python3 -m pytest tests/regression/test_critical_gap_false_positive_2506.py -q`.

## doctrine
- same-PR post-Gemini push 금지(redesign = 새 commit→new head→non-force push, amend 금지). bot `/gemini review` 무효(인간 OWNER 1회만). long polling 금지(watcher 위임).

## finalize (PR 갱신까지 — merge 금지)
1. redesign → regression PASS → `git add` 2파일 → commit → **non-force push**(PR #169 갱신).
2. `memory/reports/task-2723.md` 보고서 갱신(redesign + L1). 3. `memory/events/task-2723+3.done` 생성.
4. ANU normal callback cron 강제 등록 — collector_role=ANU, ANU_KEY=c119085addb0f8b7(sealed, literal 노출 금지). self-key 금지(SELF_COLLECTOR_FORBIDDEN). cron 0+sendfile only = NOT_REGISTERED fail-closed.
5. ★ merge 금지 — ANU/watcher 가 새 head OWNER /gemini review → CI/Gemini watcher → MERGE_READY_CANDIDATE 판정·보고.

## ★ 사후 정책 (회장 verbatim)
이번 구조적 redesign 이후에도 같은 critical_gap zero-count 계열 HIGH/CRITICAL 이 나오면 **추가 패치 금지** → PR #169 hold 또는 **alternative resolver** 로 보고. merge 회장 승인 전 금지.

## allowed_resources
```yaml
allowed_resources:
  paths:
    - "teams/shared/verifiers/critical_gap.py"
    - "tests/regression/test_critical_gap_false_positive_2506.py"
    - "memory/reports/task-2723.md"
    - "memory/events/task-2723+3.done"
  forbidden_paths:
    - "scripts/finish-task.sh"
    - "dispatch/**"
    - "deploy/systemd/**"
    - ".github/**"
  commands:
    - "pytest"
    - "python3 -m pytest"
    - "python3 -m py_compile"
  merge_policy: "none"
  ttl_hours: 48
```

## goal_assertions (auto)
- `python3 -m pytest tests/regression/test_critical_gap_false_positive_2506.py -q`
- `python3 -c "import sys; s=open('teams/shared/verifiers/critical_gap.py').read(); sys.exit(1 if 'c119085addb0f8b7' in s else 0)"`