작업 보고서

WORK_REPORT.md 기준 · 최근 SSH 답변: probe_155_source_via_web_trace_v1 · 2026-05-06 10:16:07
작업 상태 코드 지도 SSH 답변 돌아가기
/volume1/web/gpt/repair_jobs/WORK_REPORT.md 2026-05-02 11:33:36
# 영일전기철물 AI 현재 작업 보고서

generated_at: 2026-05-01 20:59:06
root: `/volume1/web/gpt`

---

## 1. 한줄판단

현재는 `/gpt` 운영자 UI, 작업 상태/보고서/코드 지도, 고객 조회/삭제 흐름, `건영아` 호출어와 마지막 명령 기준 10분 세션까지 1차 완료된 상태다. 이제부터는 기능을 막 때려넣기보다 **보고서 → 원인 위치 확인 → 작은 검증 → 패치 → 상태 갱신** 순서로 가야 한다.

---

## 2. 최근 SSH 기준

- latest_title: `code_nav_map_viewer_v1`
- latest_created_at: `2026-05-01 20:43:46`
- latest_file: `/volume1/web/gpt/repair_jobs/ssh_answers/latest.txt`

---

## 3. 현재 완료된 큰 덩어리

### A. 운영자 UI
- `/gpt/` 운영자 상태판 추가
- 하단 빠른 버튼 숨김
- SSH 답변 / 상황판 / 엔진 로그 / 기록 / 고객 점검 / 작업 상태 / 코드 지도 버튼 추가
- 엔진 로그 닫기 버튼 추가
- 기록 패널 복귀 버튼 추가

### B. 작업 복구 시스템
- `repair_jobs/WORK_STATE.md` 생성
- `/gpt/work_state.php` 생성
- 새 대화 복구문 복사 기능 추가

### C. 코드 지도 시스템
- `repair_jobs/CODE_NAV.md` 생성
- `/gpt/code_map.php` 생성
- 함수/파일 검색 가능

### D. 고객 조회/삭제 흐름
- 초성/임시명 고객 조회 라우팅 보강
- 자연어 삭제 파서 개선
- 이미 삭제된 고객은 deleted 기록 힌트 표시

### E. `건영아` 호출어
- Agent 초입 fast path 추가
- LLM/ChatTool로 안 보내는 방향
- 마지막 명령 기준 10분 sliding 세션 패치 진행

---

## 4. 코드 지도 스캔 요약

- 스캔 PHP 파일: 308개
- 클래스/인터페이스/트레이트: 220개
- 함수/메서드: 2184개

---

## 5. 지금 문제 터지면 먼저 볼 위치

### UI/버튼/패널
- `partials/operator_status.php`
- `partials/debug_drawer.php`
- `partials/history_panel.php`
- `assets/operator_overhaul.css`
- `assets/app_shell.js`

### 라우팅/답변 흐름
- `engine_modules/agent/Agent.php`
- `engine_modules/tools/ToolSelector.php`
- `engine_modules/tools/routing/RoutePipeline.php`
- `engine_modules/tools/ChatTool.php`

### 고객 조회/삭제
- `engine_modules/tools/routing/CustomerRoute.php`
- `engine_modules/tools/CustomerTool.php`
- `engine_modules/agent/Agent.php` 승인 pending 복원부

### 작업 기억/복구
- `repair_jobs/WORK_STATE.md`
- `repair_jobs/WORK_REPORT.md`
- `repair_jobs/CODE_NAV.md`
- `work_state.php`
- `code_map.php`

---

## 6. 핵심 파일 지도 확인 결과

### `engine_modules/agent/Agent.php`
- - ✅ **Agent 메인 루프/승인/호출어**: `engine_modules/agent/Agent.php`
- - `engine_modules/agent/Agent.php`
- - `engine_modules/agent/Agent.php` 승인 pending 복원부
- - `engine_modules/agent/Agent.php`
- ### `engine_modules/agent/Agent.php`

### `engine_modules/tools/ToolSelector.php`
- - ✅ **도구 선택/라우팅**: `engine_modules/tools/ToolSelector.php`
- - `engine_modules/tools/ToolSelector.php`
- - `engine_modules/tools/ToolSelector.php`
- ### `engine_modules/tools/ToolSelector.php`

### `engine_modules/tools/CustomerTool.php`
- - ✅ **고객 조회/삭제/점검**: `engine_modules/tools/CustomerTool.php`
- - `engine_modules/tools/CustomerTool.php`
- ### `engine_modules/tools/CustomerTool.php`

### `engine_modules/tools/routing/CustomerRoute.php`
- - ✅ **고객 라우트**: `engine_modules/tools/routing/CustomerRoute.php`
- - `engine_modules/tools/routing/CustomerRoute.php`
- ### `engine_modules/tools/routing/CustomerRoute.php`

### `partials/operator_status.php`
- - ✅ **운영자 패널**: `partials/operator_status.php`
- - `partials/operator_status.php`

### `partials/debug_drawer.php`
- - ✅ **엔진 로그 드로어**: `partials/debug_drawer.php`
- - `partials/debug_drawer.php`

### `partials/history_panel.php`
- - ✅ **기록 패널**: `partials/history_panel.php`
- - `partials/history_panel.php`

### `work_state.php`
- - ✅ **작업 상태 뷰어**: `work_state.php`
- ### `work_state.php`

### `code_map.php`
- - ⚠️ **코드 지도 뷰어**: `code_map.php`

---

## 7. 현재 남은 우선순위

1. 이미 삭제된 고객 안내 문구 요약형 개선
2. CODE_NAV.md 자동 갱신 스크립트 만들기
3. 작업 끝날 때 WORK_STATE.md / WORK_REPORT.md 갱신 루틴 만들기

---

## 8. 다음 GPT에게 줄 지시

```txt
현재 `/volume1/web/gpt`에서 내부망 GPT 운영자 UI, 작업 상태 시스템, 코드 지도, 고객 조회/삭제, 건영아 호출어 세션을 개선 중이다.

먼저 볼 파일:
- `/volume1/web/gpt/repair_jobs/WORK_STATE.md`
- `/volume1/web/gpt/repair_jobs/WORK_REPORT.md`
- `/volume1/web/gpt/repair_jobs/CODE_NAV.md`
- `/volume1/web/gpt/repair_jobs/ssh_answers/latest.txt`

현재 우선 작업:
1. 이미 삭제된 고객 안내 문구 요약형 개선
2. CODE_NAV.md 자동 갱신 스크립트 만들기
3. 작업 끝날 때 WORK_STATE.md / WORK_REPORT.md 갱신 루틴 만들기

주의:
- 실제 데이터 변경 금지
- 삭제/수정/등록은 승인 후만
- 테스트는 테스트 데이터만
```

---

## 추가 완료: 건영아 sliding 10분 세션

완료 시각: 2026-05-01 20:58:25

검증 완료:
- `건영아` 입력 시 짧은 랜덤 응답만 출력
- `data/runtime/geonyeong_admin_session.json` 생성
- `고객 리스트 조회`처럼 Agent를 타지 않는 web_capability 직행 명령에서도 `api.php` 앞단에서 세션 갱신
- 최종 trace 확인:
  - `[api.admin_session] active=true`
  - `[api.admin_session] timeout_policy=sliding_10_minutes_after_last_command`
  - `[api.admin_session] last_seen_refreshed=true`
  - `[api.admin_session] touch_source=before_web_capability_preflight`

관련 파일:
- `engine_modules/agent/Agent.php`
- `api.php`

판정:
- 마지막 명령 후 10분이 지나면 관리자 세션 해제되는 구조까지 완성.
---

## 추가 완료: 모듈 소속표 1차

완료 시각: 2026-05-01 21:06:45

추가된 항목:
- `repair_jobs/MODULE_OWNERSHIP.md`
- `/gpt/module_ownership.php`
- 운영자 패널 `[모듈 구조]` 버튼

1차 분석 대상:
- `api.php`
- `engine_modules/agent/Agent.php`
- `engine_modules/tools/ToolSelector.php`
- `engine_modules/tools/CustomerTool.php`
- `engine_modules/capabilities/web_preflight.php`
- `engine_modules/tools/routing/RoutePipeline.php`

판정:
- 파일 위치와 함수 지도는 잡혔지만, Agent / ToolSelector / CustomerTool은 여전히 책임이 많다.
- 다음 구조 개선은 CustomerTool 분리 또는 CODE_NAV 자동 갱신 스크립트가 적합하다.
---

## 추가 완료: 요청 흐름도 1차

완료 시각: 2026-05-01 21:18:00

추가된 항목:
- `repair_jobs/MODULE_FLOW.md`
- `/gpt/module_flow.php`
- 운영자 패널 `[흐름도]` 버튼

내용:
- 전체 요청 기본 흐름
- web_capability 직행 흐름
- Agent 일반 실행 흐름
- 승인 pending 흐름
- 고객 삭제 / 이미 삭제 힌트 흐름
- 건영아 호출어 / 세션 흐름
- UI 운영자 패널 흐름
- 터졌을 때 추적 순서

다음 문서화:
1. `MODULE_DEPENDENCY.md`
2. `MODULE_FUNCTION_GROUPS.md`
3. `REFACTOR_ROADMAP.md`
---

## 추가 완료: 의존성 지도 1차

완료 시각: 2026-05-01 21:20:22

추가된 항목:
- `repair_jobs/MODULE_DEPENDENCY.md`
- `/gpt/module_dependency.php`
- 운영자 패널 `[의존성]` 버튼

내용:
- PHP 파일 스캔
- require/include 연결
- class 선언 위치
- new/Class:: 참조 연결
- 핵심 파일별 in/out 의존성
- 의존성 기준 위험 판정

다음 문서화:
1. `MODULE_FUNCTION_GROUPS.md`
2. `REFACTOR_ROADMAP.md`
3. 문서 자동 갱신 스크립트
---

## 추가 완료: 의존성 지도 v2 정밀 재생성

완료 시각: 2026-05-01 21:22:24

수정 내용:
- `repair_jobs/logs` 제외
- `repair_jobs/backups` 제외
- `repair_jobs/ssh_answers` 제외
- `data`, `reports`, `vendor`, `node_modules` 제외
- 백업/임시/테스트성 PHP 파일명 제외
- `src_ToolSelector.php` 같은 로그 추출본이 실제 의존성으로 잡히는 문제 제거

판정:
- MODULE_DEPENDENCY.md는 이제 실제 운영 파일 중심으로 보는 기준점으로 사용 가능.
---

## 추가 완료: 의존성 지도 v3 엄격 스캔

완료 시각: 2026-05-01 21:24:12

수정 내용:
- `include/require`를 줄 시작 PHP 문장 기준으로만 인정
- JS 문자열/headers/fetch 옵션 오인식 제거
- `tools/,`, `headers: {` 같은 잘못된 의존성 제거
- 임시/로그/백업 경로 제외 유지

판정:
- MODULE_DEPENDENCY.md는 v3부터 실제 운영 파일 의존성 기준으로 사용 가능.
---

## 추가 완료: 의존성 지도 v4 PHP 빌더

완료 시각: 2026-05-01 21:25:53

수정 내용:
- `tools/build_module_dependency_v4.php` 생성
- Python 일회성 생성 대신 PHP 빌더로 재생성
- 운영 경로만 스캔
- 줄 시작 `include/require` PHP 문장만 인정
- JS 문자열/headers/fetch 옵션 오인식 제거

판정:
- MODULE_DEPENDENCY.md는 v4부터 실제 운영 의존성 기준으로 사용.
---

## 추가 완료: 함수 역할 그룹 지도 1차

완료 시각: 2026-05-01 21:28:12

추가된 항목:
- `repair_jobs/MODULE_FUNCTION_GROUPS.md`
- `/gpt/module_function_groups.php`
- `tools/build_module_function_groups_v1.php`
- 운영자 패널 `[함수그룹]` 버튼

내용:
- 진입/API/공통 앞단
- 건영아 호출어 / 관리자 세션
- Agent 실행 루프
- 승인 / pending / 고위험 실행 차단
- 라우팅 / ToolSelector / RoutePipeline
- 고객 조회 / 고객 삭제 / 고객 수정 / 고객 점검
- web_capability / Agent 우회 읽기
- 운영자 UI / 문서 뷰어

다음:
- `REFACTOR_ROADMAP.md` 생성
- 구조 문서 자동 갱신 통합 스크립트
---

## 추가 완료: 함수 역할 그룹 v2 인라인 마커 보강

완료 시각: 2026-05-01 21:29:33

수정 내용:
- `tools/build_module_function_groups_v2.php` 생성
- v1 함수명 분류 결과에 인라인/마커 기반 역할 블록 추가
- `건영아 호출어 / 관리자 세션`이 함수 0개로 보이는 문제 보정
- 고객 삭제 pending 재라우팅, 이미 삭제 고객 힌트, api web_capability 앞단 마커까지 별도 표시

판정:
- MODULE_FUNCTION_GROUPS.md는 v2부터 함수 + 인라인 블록 기준으로 사용.
---

## 기존 MD 합류 요약 v1

합류 시각: 2026-05-01 21:50:13

### 1. `reports/router_stress_matrix_100.md` 반영

핵심:
- 견적 전체 삭제, 일정 전부 삭제 같은 대량/위험 작업은 `HIGH_RISK_APPROVAL_REQUIRED`로 분류해야 한다.
- 코드 진단 요청은 `code` 계열 READ_ONLY로 가야 한다.
- 오늘 관련 deep lookup은 schedule/worklog/payment/quotation/news 같은 복합 조회 후보를 고려해야 한다.

### 2. `reports/system_safety_matrix_50.md` 반영

핵심:
- code read는 `READ_ONLY`.
- 위험 삭제는 `make_plan_then_wait_confirm`.
- 실제 변경 작업은 승인 없이 실행되면 안 된다.

### 3. `reports/data_source_map.md` 반영

핵심:
- 저장소/DB/API 출처는 도메인별로 구분해야 한다.
- GPT 내부 기억/히스토리와 ERP 업무 DB는 같은 데이터처럼 취급하면 안 된다.
- DB export 문서는 검색/백업용이지 현재 구조 설계 기준은 아니다.

### 4. 다음 구조개선 판단

우선순위:
1. ToolSelector 잔여 책임을 route/policy로 분리
2. CustomerTool 검색/삭제/점검 service 분리
3. WorklogTool execute 분리 후보는 참고만 하고, 현재 작업 범위 밖으로 둔다
4. 안전/승인 정책은 공통 policy로 고정
---

## 리팩토링 로드맵 v1

작성 시각: 2026-05-01 21:52:16

### 0. 원칙

- 새 MD를 늘리지 않는다.
- 현재 기준 문서 7개 안에서 관리한다.
- 실제 고객/현장/견적/결제 데이터 변경은 승인 후만 한다.
- 구조개선은 읽기 전용 검증 → 작은 패치 → 회귀 확인 순서로 한다.
- 원문 복붙이 아니라 요약 합류만 한다.

---

### 1순위: ToolSelector 잔여 책임 분리

이유:
- ToolSelector는 아직 라우팅 guard, safety, planner_hint, fallback, 도메인별 예외가 섞여 있다.
- 장기 목표는 ToolSelector를 얇은 브릿지로 만드는 것이다.

분리 후보:
- safety 관련 판단 → `SafetyRoute` 또는 `SafetyPolicy`
- planner hint 복구 → `PlannerHintPolicy`
- schedule overlay → `ScheduleRoute`
- stock read 예외 → `StockRoute` / `StockRule`
- fallback chat → `ChatFallbackRoute`

먼저 볼 문서:
- `MODULE_FUNCTION_GROUPS.md`
- `MODULE_OWNERSHIP.md`
- `MODULE_FLOW.md`

검증:
- 고객 조회
- 고객 삭제 승인
- 일정 조회
- 재고 조회
- 코드 진단
- 위험 삭제 승인대기

---

### 2순위: CustomerTool 분리

이유:
- CustomerTool 안에 조회, 삭제, 수정, 점검, 메시지 포맷이 같이 있다.
- 최근 `3333` 삭제 케이스처럼 삭제/이미삭제 힌트 로직이 복잡해졌다.

분리 후보:
- `CustomerSearchService.php`
- `CustomerDeleteService.php`
- `CustomerDeletedHintService.php`
- `CustomerUpdateService.php`
- `CustomerAuditService.php`

먼저 분리할 것:
1. 이미 삭제된 고객 힌트 파서
2. 고객 삭제 자연어 파서
3. 고객 조회 formatter

검증:
- `3333 도 테스트 고객이네 지워`
- `승인`
- `고객 리스트 조회`
- `ㅁㄴㅇㄹ 조회`

---

### 3순위: Agent 승인/pending 분리

이유:
- Agent.php 안에 run loop, 승인 pending, 건영아 세션, Tool 실행, 결과 정규화가 섞여 있다.
- 고위험 작업은 안정성이 중요하므로 approval 계층을 독립시키는 게 좋다.

분리 후보:
- `ApprovalPendingService.php`
- `SystemExecutionGuard.php`
- `AgentToolRunner.php`
- `AdminSessionService.php`

주의:
- `건영아` 호출어는 사용자 출력에 관리자 모드 문구를 노출하면 안 된다.
- 승인 pending은 chat으로 튀면 안 되고 원래 tool_spec을 복원해야 한다.

검증:
- `건영아`
- `고객 리스트 조회`
- 10분 sliding session trace
- 삭제 승인 pending 복원

---

### 4순위: WorklogTool 분리 후보는 보류

이유:
- 기존 MD에 WorklogTool execute 분리 후보가 많지만, 지금 당장 핵심 장애는 아니다.
- 먼저 ToolSelector / CustomerTool / Agent 안정화가 우선이다.

참고 문서:
- `repair_jobs/logs/worklogtool_split_candidates_...`
- `repair_jobs/logs/worklogtool_execute_scan_...`

현재 판단:
- 참고만 하고 지금 작업 범위에서는 뒤로 미룬다.

---

### 5순위: 문서 자동 갱신 통합

이유:
- CODE_NAV, MODULE_DEPENDENCY, MODULE_FUNCTION_GROUPS는 수동/개별 빌더가 생겼다.
- 나중에는 한 번에 갱신하는 통합 명령이 필요하다.

후보:
- `tools/build_module_dependency_v4.php`
- `tools/build_module_function_groups_v2.php`
- 추후 `tools/build_module_docs.php`

주의:
- 자동 갱신은 기준 문서 7개 안에서만 한다.
- `git_sources`, `vendor`, `data/db_exports`, `repair_jobs/backups`, `repair_jobs/logs`는 기본 제외한다.

---

### 다음 실제 작업

추천 순서:
1. ToolSelector 잔여 책임 중 safety/planner_hint 위치 확인
2. ToolSelector에서 바로 분리 가능한 작은 route/policy 후보 1개 선택
3. 읽기 전용 smoke 작성
4. 패치
5. 회귀 확인
---

## 추가 완료: ScheduleOverlayPolicy bridge v1

완료 시각: 2026-05-01 21:58:05

변경:
- `engine_modules/routing/ScheduleOverlayPolicy.php` 생성
- `PlannerHintAdapter.php`에서 `schedule_overlay` hint를 ScheduleOverlayPolicy로 위임
- `ToolSelector.php`의 기존 schedule_overlay 연간/놓친 일정 fallback 앞에 policy bridge 추가
- 기존 ToolSelector fallback은 삭제하지 않고 안전 fallback으로 유지

검증:
- `올해 일정에서 놓친 게 있나` → schedule / `YYYY년 일정 요약`
- `2026년 일정 요약` → schedule / `2026년 일정 요약`
- `2026년 4월 일정` → policy 미대상
- `safety_block` 기존 PlannerHintAdapter 흐름 유지

판정:
- schedule_overlay 분리 1차 완료.
- 다음은 live route smoke로 기존 일정/고객/위험삭제 흐름 영향 확인.
---

## 추가 진행: ScheduleOverlayPolicy live smoke v1

진행 시각: 2026-05-01 21:59:30

확인 질의:
- `올해 일정에서 놓친 게 있나`
- `2026년 4월 일정`
- `고객 리스트 조회`
- `견적 전체 삭제해줘`

판정 기준:
- 연간/놓친 일정만 ScheduleOverlayPolicy가 처리
- 월간 일정은 policy 미대상
- 고객 조회 영향 없음
- 위험 삭제는 실제 실행 금지, 승인/차단/계획 흐름이어야 함
---

## 완료 처리: ScheduleOverlayPolicy 1차 분리

완료 시각: 2026-05-01 22:00:52

결과:
- `ScheduleOverlayPolicy.php` 생성 완료
- `PlannerHintAdapter.php`에서 `schedule_overlay` hint 연결 완료
- `ToolSelector.php` 기존 schedule_overlay fallback 앞에 policy bridge 추가 완료
- 기존 fallback 블록은 삭제하지 않고 안전장치로 유지

live smoke 판정:
- `올해 일정에서 놓친 게 있나` → `2026년 일정 요약`으로 정규화, schedule 실행
- `2026년 4월 일정` → policy 미대상, 월간 일정 경로 유지
- `고객 리스트 조회` → data_lookup/customer_list 유지
- `견적 전체 삭제해줘` → 실제 삭제 안 됨, system_pending 승인대기 저장

최종 판정:
- `SCHEDULE_OVERLAY_POLICY_LIVE_SMOKE_OK`

다음 후보:
- ToolSelector 안의 남은 planner_hint / fallback_chat / stock_read_exception 중 작은 것부터 추가 분리 검토
---

## 완료 처리: stock_read_exception legacy marker 정리

완료 시각: 2026-05-01 22:04:33

판정:
- `SafetyHintPolicy.php`가 stock read 예외 판단을 담당한다.
- `ToolSelector.php` 내부에는 실제 `stock_read_exception` legacy method가 없다.
- 기존 `SAFETY_STOCK_READ_EXCEPTION_V1_METHODS` 마커는 오해를 줄 수 있어 `MIGRATED_TO_SAFETY_HINT_POLICY`로 정리했다.
- 기능 변경은 없고 주석/마커 정리만 수행했다.

검증:
- `차단기 얼마야` → stock read 예외 매칭
- `누전차단기 재고 있어` → stock read 예외 매칭
- `다운라이트 몇개 남았어` → stock read 예외 매칭
- `차단기 내려` → 미매칭
- `릴레이 켜` → 미매칭
- `고객 리스트 조회` → 미매칭

다음 후보:
- Planner hint observer/fallback 정리 감사
- fallback_chat 정리는 영향 범위가 커서 보류
---

## 추가 완료: stock_read_exception 잔여 주석 정리

완료 시각: 2026-05-01 22:05:59

내용:
- `ToolSelector.php` catch 구간에 남아 있던 `기존 SAFETY_STOCK_READ_EXCEPTION_V1 fallback` 표현 정리
- 실제 legacy method는 없으므로, 실패 시 일반 라우팅 흐름으로 진행한다는 표현으로 수정
- 기능 변경 없음
---

## 추가 완료: PlannerHintContextResolver v1 독립 생성

완료 시각: 2026-05-01 22:08:45

내용:
- `engine_modules/routing/PlannerHintContextResolver.php` 생성
- ToolSelector 내부의 router_kernel/planner_hint context 추출 및 fallback recompute 분리 준비
- 이번 단계에서는 ToolSelector 실행 흐름을 아직 바꾸지 않았다.
- 단독 스모크로 schedule_overlay, intent_rule guard, memory guard, 위험 삭제 approval recompute를 확인했다.

다음:
- Resolver 결과가 기존 ToolSelector trace와 같은지 live 비교
- 이후 ToolSelector observer/fallback 블록을 Resolver 호출로 대체할지 판단
---

## 추가 진행: PlannerHintContextResolver live 비교 smoke v1

진행 시각: 2026-05-01 22:10:06

목적:
- ToolSelector bridge 적용 전에 현재 live route와 Resolver 단독 결과를 비교한다.
- 이번 단계에서도 ToolSelector 실행 흐름은 변경하지 않는다.

확인 질의:
- `올해 일정에서 놓친 게 있나`
- `2026년 4월 일정`
- `히스토리에 저장해줘`
- `고객 리스트 조회`
- `견적 전체 삭제해줘`
- `차단기 얼마야`
- `차단기 내려`

다음 판단:
- live route와 Resolver 결과가 크게 어긋나지 않으면 ToolSelector observer/fallback 블록을 Resolver 호출로 치환할 수 있는지 검토한다.
---

## 추가 완료: PlannerHintContextResolver stock read guard v1

완료 시각: 2026-05-01 22:16:28

내용:
- `PlannerHintContextResolver.php`에 stock read exception guard 추가
- `SafetyHintPolicy::makeStockReadExceptionSpec()`가 매칭되는 가격/재고/수량 조회는 Resolver에서 `tool_hint=stock`으로 고정
- 목적은 `차단기 얼마야` 같은 재고 조회가 Resolver fallback에서 `safety_block`으로 오염되는 문제 방지

검증:
- 50개 입력 재감사 수행
- 기대값: `resolver_stock_read_pollution_risk=0`
- 기대값: `physical_wrong_stock_exception=0`

다음:
- live 비교 smoke 재실행
- 결과 정상 시 ToolSelector observer/fallback bridge 적용 여부 판단
---

## 정정 완료: PlannerHintContextResolver stock guard 메서드 누락 수정

완료 시각: 2026-05-01 22:17:55

이전 실패:
- `makeStockReadExceptionGuard()` 호출부는 들어갔지만 실제 private method가 누락되어 fatal 발생
- 원인: 스크립트가 호출문 문자열을 보고 method already exists로 오판

이번 수정:
- 실제 `private static function makeStockReadExceptionGuard()` 존재 여부를 정규식으로 확인
- 누락된 메서드 삽입
- 50개 입력 재감사 수행

다음:
- `recommendation=STOCK_GUARD_OK_RUN_LIVE_COMPARE_NEXT` 확인 후 live 비교 smoke 재실행
---

## 추가 진행: PlannerHintContextResolver stock guard 후 live 비교 smoke v1

진행 시각: 2026-05-01 22:19:24

목적:
- stock read guard 적용 후 live route와 Resolver 단독 결과 비교
- 아직 ToolSelector 실행 흐름은 변경하지 않음

확인 질의:
- `올해 일정에서 놓친 게 있나`
- `2026년 4월 일정`
- `고객 리스트 조회`
- `견적 전체 삭제해줘`
- `차단기 얼마야`
- `릴레이 가격 알려줘`
- `차단기 내려`
- `타이머 가동해`

다음 판단:
- 재고/가격 조회가 live와 Resolver 모두 stock으로 맞으면 bridge 가능성 검토
- `타이머 가동해` live 결과에 따라 ToolRoutePlanner 물리동작 패턴 보강 여부 판단
---

## 추가 완료: SafetyPhysicalControlPolicy v1

완료 시각: 2026-05-01 22:21:30

목적:
- `타이머 가동해` 같은 실제 물리 동작 요청이 chat/auto로 빠지는 안전 구멍 보강
- 가격/재고/수량 조회는 stock read 예외가 먼저 처리되므로 safety_block으로 오염되지 않게 유지

변경:
- `engine_modules/routing/SafetyPhysicalControlPolicy.php` 생성
- `ToolSelector.php`에 `SAFETY_PHYSICAL_CONTROL_POLICY_V1_BRIDGE` 추가
- bridge 위치는 SafetyHintPolicy stock read 예외 다음, PlannerHintAdapter 이전

검증:
- `타이머 가동해` → safety_block 기대
- `차단기 내려` → safety_block 유지
- `차단기 얼마야` → stock 유지
- `릴레이 가격 알려줘` → stock 유지
- `차단기 내려 말고 가격만 알려줘` → safety_block 미대상

다음:
- live smoke 결과 확인 후 PlannerHintContextResolver bridge 적용 여부 재판단
---

## 추가 진행: PlannerHintContextResolver 병렬 trace v1

진행 시각: 2026-05-01 22:24:10

변경:
- `ToolSelector.php`에 `PLANNER_HINT_CONTEXT_RESOLVER_PARALLEL_TRACE_V1` 추가
- Resolver 결과를 trace에만 남긴다.
- 실제 ToolSelector 선택 결과는 변경하지 않는다.

목적:
- 기존 ToolSelector 판단과 Resolver 판단을 live에서 비교
- 바로 치환하지 않고 안전하게 차이를 관찰

확인 질의:
- `올해 일정에서 놓친 게 있나`
- `2026년 4월 일정`
- `고객 리스트 조회`
- `견적 전체 삭제해줘`
- `차단기 얼마야`
- `릴레이 가격 알려줘`
- `차단기 내려`
- `타이머 가동해`
- `차단기 내려 말고 가격만 알려줘`

다음:
- 병렬 trace 결과가 안정적이면 observer/fallback 블록 치환 검토
- 불일치가 있으면 Resolver 보강 후 다시 비교
---

## 추가 완료: MODULE_FUNCTION_GROUPS v3 재정리

완료 시각: 2026-05-01 22:27:54

내용:
- `MODULE_FUNCTION_GROUPS.md`를 v3로 재정리
- 새 MD 생성 없음
- 새 Policy/Resolver 파일을 스캔 대상에 포함
- 완료/보류/다음 분리 후보를 명확히 표시
- `REFACTOR_ROADMAP.md` 생성 문구 제거
- 다음 작업을 CustomerTool 분리 감사로 정리
---

## 추가 완료: CustomerDeletedHintService v1 독립 생성

완료 시각: 2026-05-01 22:31:45

내용:
- `engine_modules/tools/customer/CustomerDeletedHintService.php` 생성
- 기존 `CustomerTool::findDeletedCustomerExportHintV1()` 분리를 위한 독립 서비스
- 이번 단계에서는 CustomerTool 실행 흐름은 아직 변경하지 않음
- db_exports의 deleted/is_active=0 기록을 읽어 사람용 요약으로 만드는 읽기성 서비스

다음:
- 기존 CustomerTool 내부 함수와 서비스 출력 비교
- 출력이 같으면 CustomerTool에서 CustomerDeletedHintService를 호출하도록 bridge 적용
---

## 추가 완료: CustomerDeletedHintService bridge v1

완료 시각: 2026-05-01 22:32:58

내용:
- `CustomerTool::findDeletedCustomerExportHintV1()` 내부에 CustomerDeletedHintService bridge 추가
- 기존 인라인 파서는 fallback으로 유지
- 실제 고객 삭제 로직은 변경하지 않음
- db_exports deleted/is_active=0 힌트 생성만 서비스로 위임

검증:
- `3333 도 테스트 고객이네 지워`
- `ㅁㄴㅇㄹ 삭제해`
- `없는고객테스트 삭제해`

다음:
- live smoke 결과 확인 후 CustomerDeletedHintService 분리 완료 처리
- 이후 CustomerDeleteService 전체 분리는 별도 감사 후 진행
---

## 완료 처리: web_preflight 저장 의도 bypass guard v1

완료 시각: 2026-05-02 10:46:09

원인:
- `api.php`가 Agent/ToolSelector보다 먼저 `gpt_web_capability_preflight()`를 호출한다.
- `gpt_web_capability_preflight()` 안에서 `gpt_web_review_preflight()`가 저장 요청을 성과/회고 질문으로 오분류했다.
- `gpt_web_review_preflight()`에는 저장/기록/메모 생성 요청을 막는 guard가 없었다.
- trace의 “잘한/제일/성과/현장/사업 운영” 문구는 실제 매칭 근거가 아니라 고정 설명문이었다.

변경:
- `web_preflight.php`에 `gpt_web_is_save_intent_bypass_v1()` 추가
- `gpt_web_review_preflight()` 초입에 저장 의도 bypass guard 추가
- `gpt_web_capability_preflight()` 초입에도 저장 의도 bypass guard 추가
- 저장/기록/메모 생성 요청은 web_preflight 전체를 우회하고 ToolSelector/Agent로 내려간다.

검증:
- `오늘 서울 다녀온 거 저장해줘` → review_preflight null 기대
- `오늘 서울 다녀온 거 저장해줘` → capability_preflight null 기대
- `2026년에 내가 가장 잘한 일 뭐야` → review_preflight 유지 기대

주의:
- 이번 명령은 실제 저장 API 호출을 하지 않았다.
- live 저장 테스트는 별도 확인 후 진행한다.
---

## 추가 진행: web_preflight 저장 의도 bypass live smoke

진행 시각: 2026-05-02 10:47:52

목적:
- 함수 단독 테스트가 아니라 실제 API 전체 흐름에서 저장 요청이 성과/회고 preflight로 가지 않는지 확인
- 저장 요청이 ToolSelector/Agent의 memory/history 저장 라우트로 내려가는지 확인

확인 질의:
- `GPT 저장 라우팅 테스트 ... 저장해줘`
- `오늘은 애들 데리고 서울 지하철 ... 저장해줘`
- `2026년에 내가 가장 잘한 일 뭐야`

판정:
- 저장 요청에서 `review_preflight`가 보이면 실패
- 저장 요청에서 `memory/history_memo/memory_create`가 보이면 정상
- 성과 질문에서 `review_preflight`가 유지되면 정상
---

## 완료 처리: HistoryMemoTool cleanContent 날짜 조사 찌꺼기 수정 v1

완료 시각: 2026-05-02 11:01:15

원인:
- `cleanContent()`가 문장 앞의 `오늘/어제/그제/그저께`만 제거하고 뒤 조사 `은/는`을 제거하지 않았다.
- 예: `오늘은 애들 데리고...` → `은 애들 데리고...`
- 예: `어제는 애들 드리고...` → `는 애들 드리고...`

변경:
- `오늘/어제/그제/그저께` 뒤의 `은/는/이/가/의/에` 조사를 같이 제거
- `2026년 5월 2일은`, `5월 2일은` 같은 명시 날짜 뒤 조사도 같이 제거

검증:
- 실제 DB 저장 호출 없이 `cleanContent()` 단독 테스트 수행
- `오늘은 애들 데리고... 저장해줘` → `애들 데리고...`
- `어제는 애들 드리고... 저장해줘` → `애들 드리고...`

주의:
- 기존에 이미 저장된 `은 애들...`, `는 애들...` 기록은 아직 수정하지 않았다.
- 기존 DB row 보정은 별도 승인 후 진행한다.
---

## 추가 완료: HistoryMemoTool 저장 후 보완 질문 레이어 v1

완료 시각: 2026-05-02 11:06:43

목적:
- 히스토리 저장 후 단순히 “저장됨”으로 끝내지 않고 부족한 정보/애매한 표현/오타 의심을 질문으로 보여준다.
- 사용자가 다음 메시지에서 추가/덮어쓰기할 수 있게 유도한다.

변경:
- `analyzeSavedHistoryQuality()` 추가
- `formatSavedHistoryQualityFollowup()` 추가
- 저장 시 `meta_json`에 `quality_score`, `missing_fields`, `quality_flags`, `followup_questions` 저장
- 응답 메시지에 `🔍 보완하면 더 좋은 부분` 섹션 추가

주의:
- 이번 단계는 질문 생성만 한다.
- “방금 저장한 기록 덮어쓰기/추가” 기능은 아직 구현하지 않았다.
- 실제 저장 API 호출 없이 단독 테스트만 수행했다.
---

## 추가 진행: HistoryMemoTool 저장 후 보완 질문 live smoke v1

진행 시각: 2026-05-02 11:09:34

목적:
- 실제 API 저장 응답에서 `🔍 보완하면 더 좋은 부분`이 나오는지 확인
- `오늘은/어제는` 조사 찌꺼기 없이 저장되는지 확인
- 저장 요청이 `review_preflight`로 다시 빠지지 않는지 확인

확인 질의:
- `오늘은 애들 데리고 서울 지하철 타고 왔어 디지털 놀이터도 가보고 지하철타고 서울도 돌아보고왔어 저장해줘`
- `디지털 놀이터 히스토리 조회`

판정 기준:
- `selected_tools=history_memo`
- `post_save_audit` trace 존재
- 응답에 `🔍 보완하면 더 좋은 부분` 존재
- `내용: 애들 데리고...`로 시작
- `내용: 은 애들...`, `내용: 는 애들...` 없어야 함
---

## 추가 완료: HistoryMemoTool 방금 저장한 기록 수정 루프 v1

완료 시각: 2026-05-02 11:13:11

목적:
- 저장 후 보완 질문에 답하면, 방금 저장한 히스토리를 추가/덮어쓰기할 수 있게 하는 1차 루프
- 예: `방금 저장한 기록에 장소는 서울상상나라였어 추가해줘`
- 예: `방금 저장한 거 ... 로 덮어써줘`

변경:
- `HistoryMemoTool::isLastRecordUpdateQuery()` 추가
- `HistoryMemoTool::executeUpdateLastRecord()` 추가
- `HistoryMemoTool::extractLastRecordUpdateContent()` 추가
- `ToolSelector`에 last record update route 추가

주의:
- 이번 단계는 코드 패치 + 단독 테스트만 수행
- 실제 DB row 수정 live smoke는 아직 하지 않음
- 현재 구현은 `personal_memo_inbox`에서 최신 `tag=history` 1건을 대상으로 함
---

## 복구 완료: HistoryMemoTool 방금 저장한 기록 수정 루프 v1

완료 시각: 2026-05-02 11:16:16

원인:
- ToolSelector route 삽입 anchor가 문자열 `"history memo route v1"` 내부를 잡아 PHP 문법이 깨졌다.
- `최근 메모 고쳐줘 장소는 ...` 형태에서 앞쪽 명령어 `고쳐줘`가 제거되지 않았다.

복구:
- `ToolSelector.php`를 직전 백업으로 복원 후 안전 anchor에 route 재삽입
- `HistoryMemoTool::extractLastRecordUpdateContent()`에서 앞쪽 수정/추가 명령어 제거 보정

주의:
- 이번 단계는 코드 복구 + 단독 테스트
- 실제 DB row 수정 live smoke는 아직 하지 않음
---

## 복구 완료: HistoryMemoTool update loop repair v2

완료 시각: 2026-05-02 11:19:42

처리:
- `ToolSelector.php` 문법 정상 재확인
- `HistoryMemoTool::extractLastRecordUpdateContent()` 선행 명령어 제거 v2 적용
- `SynologyFileReadTool.php`의 `class true` fatal이 있으면 안전 class명으로 복구

주의:
- 이번 단계는 코드 복구 + 단독 테스트
- 실제 DB row 수정 live smoke는 아직 하지 않음
---

## 복구 완료: SynologyFileReadTool true|string 타입 호환성 수정 v1

완료 시각: 2026-05-02 11:21:11

원인:
- `SynologyFileReadTool::validatePath()` 반환 타입이 `true|string`이었다.
- 현재 PHP 실행 환경에서 `true` 단독 타입을 지원하지 않아 `Cannot use 'true' as class name` fatal 발생.

변경:
- `true|string` → `bool|string`
- 성공 시 `true`, 실패 시 문자열 반환 구조는 유지

연결 이슈:
- 이 fatal 때문에 `tools/bootstrap.php` 로딩 smoke가 막혔다.
- HistoryMemoTool 방금 저장한 기록 수정 루프 테스트가 bootstrap 단계에서 중단됐다.
---

## 추가 완료: HistoryMemo update route v2 보정

완료 시각: 2026-05-02 11:27:52

문제:
- `마지막 히스토리 ... 덮어써줘`가 history_search로 먼저 잡혔다.
- 응답 예시에 넣은 `장소는 ○○였어 추가해줘`가 history_memo로 잡히지 않았다.

변경:
- ToolSelector의 last record update route를 `selectTools()` 초입으로 이동
- `장소는 ... 추가해줘`, `애들은 ... 추가해줘` 같은 직접 보완 답변도 history_memo로 라우팅
- HistoryMemoTool의 update query 감지도 직접 보완 답변을 허용

주의:
- 실제 DB 수정 live smoke는 아직 하지 않음
---

## 추가 진행: HistoryMemo 방금 저장한 기록 append live smoke v1

진행 시각: 2026-05-02 11:30:02

목적:
- 테스트 히스토리 1건을 새로 저장한 뒤, 그 최신 기록에 `장소는 서울상상나라였어 추가해줘`를 append 수정
- 저장 후 보완 질문 답변이 history_memo update 루프로 이어지는지 확인

주의:
- 실제 테스트 히스토리 1건 생성
- 최신 history row 1건에 append 수정 발생
- 실제 고객/현장/견적/결제 데이터 변경 없음
---

## 운영 원칙 추가: 테스트 데이터 표식 정책 v1

기록 시각: 2026-05-02 11:33:36

문제:
- 테스트용 히스토리/일정/견적/수금/현장 데이터가 실제 데이터처럼 남으면 나중에 찾고 지우기 어렵다.
- 특히 승인대기 작업은 query만 남으면 어떤 row를 수정할지 헷갈릴 수 있다.

원칙:
1. 모든 live smoke 테스트 데이터는 본문 맨 앞에 `[TEST]`를 붙인다.
2. 테스트 종류를 함께 붙인다.
   - 예: `[TEST][history_memo_update_loop]`
   - 예: `[TEST][schedule_create_smoke]`
   - 예: `[TEST][quotation_create_smoke]`
3. 반드시 cleanup_key를 붙인다.
   - 예: `[cleanup_key=20260502_112958]`
4. 테스트 pending 승인 전에는 대상이 테스트 데이터인지 확인한다.
5. target id 또는 cleanup_key가 없는 pending write는 승인하지 않는다.
6. 실제 고객/현장/견적/결제 데이터는 테스트 대상으로 쓰지 않는다.

앞으로 테스트 문장 예시:
- `[TEST][history_memo_update_loop][cleanup_key=20260502_112958] 오늘은 애들 데리고 서울 지하철 타고 왔어 저장해줘`
- `[TEST][schedule_create_smoke][cleanup_key=20260502_120000] 5월 10일 테스트 일정 저장해줘`

현재 확인된 기존 테스트 키:
- `GPT수정루프테스트_20260502_112958`

주의:
- 이 기록은 정책 추가이며 기존 DB row를 삭제하거나 수정하지 않는다.