# Milestone: 에이전트 작업성 중심 저장소 구조 리팩터링

## 위치

- Roadmap: [ROADMAP.md](../../../../ROADMAP.md)
- Phase: [PHASE.md](../../../../phase/automation-runtime-bridge/PHASE.md)

## 목표

생성물과 대형 데이터 파일을 제외한 사람이 관리하는 프로젝트 소스와 테스트를 책임과 변경 이유가 드러나는 단위로 재구성한다.
기존 API, wire, config schema와 런타임 동작을 유지하면서 에이전트가 한 기능을 수정하기 위해 읽어야 하는 파일 수와 task-local context를 줄이고, 이후 변경에서 다시 거대 파일이 생기지 않도록 측정 가능한 기준선을 둔다.

## 상태

[완료]

## 승격 조건

- 없음

## 구현 잠금

- 상태: 해제
- SDD: 불필요
- SDD 문서: 없음
- SDD 사유: 외부 API/proto/config schema나 runtime 책임 경계를 바꾸지 않고 동일 패키지 내 책임 분리, 테스트 재배치와 저장소 위생 개선을 수행하는 동작 보존형 리팩터링이다.
- 잠금 해제 조건: 없음
- 결정 필요: 없음

## 범위

- 추적 중인 빌드 바이너리와 파일 길이 측정 노이즈를 정리하고, 생성물·lockfile·PBX·대형 fixture 예외를 구분하는 저장소 가독성 기준선을 둔다.
- `apps/edge/internal/openai`, `apps/edge/internal/service`, `apps/edge/cmd/edge`, `apps/node/internal/node`, `apps/node/internal/adapters`, `apps/control-plane/cmd/control-plane`, `packages/go/config`, Flutter client와 E2E script의 거대 파일을 책임과 변경 이유 기준으로 분해한다.
- 거대 테스트 파일을 기능 시나리오별로 나누고, 만능 fake와 반복 fixture setup을 feature-local stub/helper로 정리한다.
- 120줄 이상 장기 함수, 과도한 parameter list와 closure 기반 상태 처리를 명명된 context/session 객체와 단계별 함수 후보로 정리한다.
- `agent-test` inventory의 canonical 데이터는 유지하면서 프로젝트 전용 query 경로로 전체 읽기 비용을 줄인다.
- `agent-ops/rules/common/**`와 `agent-ops/skills/common/**`는 공유 Agent-Ops 경계이므로 이 프로젝트 리팩터링의 측정·수정·분해 대상에서 제외한다.
- 파일 이동 뒤 domain rule, agent-spec source evidence와 현재 계약 포인터가 실제 구현 경로를 계속 가리키도록 동기화한다.

## 기능

### Epic: [hygiene] 저장소 노이즈와 가독성 기준선

에이전트 탐색을 오염시키는 artifact를 제거하고 신규 구조 부채를 조기에 확인할 수 있는 기준을 만든다.

- [x] [tracked-artifacts] 루트의 추적 중 ELF 빌드 산출물 `node`, `edge`, `openai.test`를 Git 추적에서 제거하고 공식 빌드 산출 위치와 ignore 규칙을 정렬한다. Git history 재작성은 수행하지 않는다. 검증: `git ls-files node edge openai.test`가 비어 있고 공식 build target이 `build/` 아래 산출물을 만든다.
- [x] [readability-baseline] 생성물과 data-only 예외를 제외한 파일 LOC, 함수 크기와 task-local read set을 점검하는 기준선과 ratchet 정책을 둔다. 기본 code/test 입력은 Git이 추적하는 Go/Dart/Shell/Python/Kotlin/Swift 파일로 정의하고 protobuf·Dart 생성 경로와 공유 Agent-Ops common 경계는 제외한다. 운영 파일 500줄 경고/800줄 분리 검토/1,000줄 예외, 테스트 800줄 경고/1,000줄 분리 검토, 함수 80줄 경고/120줄 분리 검토, 프로젝트 전용 Skill 진입 파일 300줄 경고/500줄 분리 검토를 기본값으로 기록한다. 검증: 동일 입력에서 재현 가능한 audit 결과가 생성되고 신규 초과 또는 기존 초과 증가가 실패하거나 명시적 allowlist 사유를 요구한다.

### Epic: [tests] 기능 시나리오 기반 테스트 분해

기능 변경 시 관련 테스트와 fixture만 읽어도 회귀 조건을 이해할 수 있게 테스트 토폴로지를 재구성한다.

- [x] [openai-tests] `apps/edge/internal/openai/server_test.go`를 auth/routes/models, chat handler/stream, Responses, provider tunnel, workspace/metadata, tool parsing/validation 시나리오로 분리하고 거대 `fakeRunService`를 feature-local stub 또는 함수 필드 기반 test double로 축소한다. 검증: `go test ./apps/edge/internal/openai`가 통과하고 기존 테스트 케이스가 누락되지 않는다.
- [x] [core-tests] `packages/go/config/config_test.go`, `apps/node/internal/node/node_test.go`, `apps/edge/internal/service/model_queue_test.go`, `apps/edge/internal/service/service_test.go`, `apps/edge/internal/bootstrap/runtime_test.go`를 config 영역과 run/cancel/command/refresh/tunnel, admission/scheduling/long-context/snapshot, runtime refresh 책임별로 분리하고 반복 setup을 명시적 helper로 정리한다. 검증: `go test ./packages/go/config ./apps/node/internal/node ./apps/edge/internal/service ./apps/edge/internal/bootstrap`가 통과한다.
- [x] [adapter-command-tests] `apps/node/internal/adapters`의 1,000줄 이상 adapter/CLI 테스트와 `apps/edge/cmd/edge`, `apps/control-plane/cmd/control-plane`, `apps/edge/internal/configrefresh`의 거대 command/config refresh 테스트를 실행 모드와 command 책임별로 분리한다. 검증: 대상 패키지 테스트가 통과하고 audit 결과에 사유 없는 1,000줄 초과 테스트가 남지 않는다.
- [x] [client-tests] `apps/client/test/widget_test.dart`를 app shell과 panel/integration 시나리오별 파일로 분리하고 공통 harness가 개별 테스트 의도를 가리지 않게 축소한다. 검증: `make client-test`가 통과한다.

### Epic: [modules] 동일 패키지 내 책임 중심 소스 분해

새 package/API를 먼저 만들지 않고 기존 package 경계를 유지한 채 파일명만으로 주요 책임을 찾을 수 있게 한다.

- [x] [openai-modules] `types.go`, `stream.go`, `chat_handler.go`, `responses_handler.go`를 chat/Responses DTO, text tool parser, schema/command normalization, normalized SSE, provider tunnel/rewrite, route/policy 책임별 파일로 분리한다. 검증: 공개·내부 동작 계약을 바꾸지 않고 `go test ./apps/edge/internal/openai`가 통과한다.
- [x] [config-modules] `packages/go/config/config.go`를 Node/Edge/provider/adapter 타입, load/default, normalization, validation 책임별 파일로 분리하고 테스트 파일과 대응시킨다. 검증: config 예시 roundtrip과 `go test ./packages/go/config`가 통과한다.
- [x] [service-node-modules] Edge `run_dispatch.go`/`model_queue.go`와 Node `node.go`를 run/provider resolution/provider pool/tunnel/cancel/session, admission/release/snapshot, run/tunnel/command/refresh/sink 책임별 파일로 분리한다. 검증: `go test ./apps/edge/internal/service ./apps/node/internal/node`가 통과한다.
- [x] [secondary-modules] OpenAI-compatible/vLLM/Ollama/CLI adapter, Flutter runtime panel, E2E shell처럼 500~800줄 이상인 후순위 후보를 동일한 책임/변경 이유 기준으로 분해하고, 단순 LOC 충족을 위한 micro-package나 `utils` 집합은 만들지 않는다.

### Epic: [complexity] 장기 함수와 상태 전달 구조화

파일 이동만으로 남는 함수 내부 인지 복잡도를 명명된 상태와 단계별 처리 경계로 낮춘다.

- [x] [stream-session] `streamChatCompletion`의 content/reasoning/tool/usage/trace 상태와 terminal event 처리를 명명된 stream session/context와 event별 단계로 분리한다. 검증: live SSE, buffered strict output, tool-call, cancel/timeout, usage 회귀 테스트가 통과한다.
- [x] [dispatch-context] 10개 이상 parameter를 전달하는 Chat/Responses/provider-pool 경로를 명명된 request/dispatch context로 바꾸고, queue reservation과 release의 성공/실패 경로를 한눈에 추적할 수 있게 한다.
- [x] [long-functions] 120줄 이상 함수의 책임 혼합 여부를 점검하고 `Classify`, adapter `Execute`, Node/transport handler와 E2E orchestration을 단계별 함수로 축소하거나 응집된 예외 사유를 남긴다.

### Epic: [agent-context] 구조화 인벤토리 읽기 비용 절감

큰 프로젝트 인벤토리는 필요한 조각만 결정적으로 조회할 수 있게 한다.

- [x] [inventory-query] `agent-test/dev/inventory.yaml`과 `agent-test/dev-corp/inventory.yaml`의 canonical machine-readable 역할은 유지하면서 env/model/node/provider selector로 필요한 bounded 결과만 얻는 결정적 query 경로를 제공한다.
- [x] [evidence-links] 활성 코드의 bare SDD section anchor를 현재 invariant 또는 contract/spec 식별자로 보강하고, 파일 분해 뒤 domain rule과 agent-spec `source_evidence`가 실제 현재 경로를 가리키도록 갱신한다.

### Epic: [verification] 동작 보존과 가독성 회귀 검증

구조 변경이 사용자 실행 계약을 바꾸지 않았고 새 기준선이 실질적인 읽기 범위 축소로 이어졌음을 검증한다.

- [x] [regression] 전체 Go/Flutter 회귀와 변경 범위의 E2E/full-cycle 검증을 수행한다. 검증: `go test ./...`, `make client-test`와 testing domain rule이 요구하는 관련 smoke/full-cycle 경로가 통과한다.
- [x] [read-set] 대표 프로젝트 변경 시나리오인 OpenAI chat stream, provider-pool dispatch, Node config refresh, Flutter runtime panel마다 필수 규칙·주요 소스·직접 테스트 파일 목록과 LOC 합계를 재현 가능한 audit evidence로 남긴다. 각 task-local read set은 가능한 경우 1,500~2,000줄 안으로 축소하고, 공유 Agent-Ops common 경로는 포함하지 않는다.

## 완료 리뷰

- 상태: 통과
- 요청일: 2026-07-19
- 완료 근거: [전체 저장소 회귀](../../../../../agent-task/archive/2026/07/m-agent-readable-repository-refactor/14_repository_regression/complete.log)와 [runtime full-cycle](../../../../../agent-task/archive/2026/07/m-agent-readable-repository-refactor/15+14_runtime_full_cycle/complete.log)이 PASS했고, 후자는 현재 구현 HEAD에서 Go/Flutter/readability 회귀와 E2E 및 실제 CLI 4종 검증을 완료했다.
- 완료 근거: 모든 기능 Task가 evidence와 함께 충족됐고 구현 잠금과 SDD 차단 항목이 없다.
- 코드레벨 감사: 현재 소스가 runtime full-cycle 검증 커밋과 동일하며, 현재 워크트리에서 Go/Flutter/readability/E2E 회귀를 다시 통과했다. 리팩터링 전 통합 테스트를 가리키던 활성 계약 포인터는 현재 분할 테스트 경로로 보정했다.
- Spec sync: Spec update not needed. 관련 현재 구현 스펙인 [Edge-Node 실행](../../../../../agent-spec/runtime/edge-node-execution.md), [Provider Pool Config Refresh](../../../../../agent-spec/runtime/provider-pool-config-refresh.md), [OpenAI-compatible 입력 표면](../../../../../agent-spec/input/openai-compatible-surface.md)의 source evidence와 불변식이 현재 코드와 일치한다.
- 검토 항목:
  - [x] 생성물 예외를 제외한 P0/P1 거대 파일이 기준선 아래로 분해되거나 명시적 예외 근거를 가진다
  - [x] 전체 Go/Flutter 회귀와 관련 E2E/full-cycle 검증이 통과한다
  - [x] 공유 Agent-Ops common 경계가 프로젝트 readability 측정·수정 대상에서 제외되고 마일스톤 중 유입된 common 변경이 복구된다
  - [x] domain rule, agent-spec, contract pointer가 이동된 현재 코드 경로와 일치한다
- agent-ui 상태 반영: 해당 없음
- 리뷰 코멘트: 종료 차단 이슈 없음. 작은 계약 포인터 불일치는 검증 후 즉시 보정했다.

## 범위 제외

- OpenAI-compatible/A2A API, proto wire, config schema, runtime routing 정책의 기능 변경
- LOC를 맞추기 위한 package 남발, 타입 하나당 파일 하나 생성, 범용 `utils`/`common` 패키지 승격
- protobuf/Dart 생성물, lockfile, PBX project, data-only fixture에 대한 동일 LOC 제한 강제
- 기존 Git history에서 binary blob을 제거하는 history rewrite
- archive 문서 재포맷이나 과거 완료 작업의 일반 컨텍스트 로딩
- `agent-ops/rules/common/**`, `agent-ops/skills/common/**`의 규칙·스킬·템플릿 변경 또는 프로젝트 readability ratchet 편입
- 리팩터링 과정에서 발견한 신규 제품 기능의 동시 구현

## 작업 컨텍스트

- 관련 경로: `apps/edge/internal/openai`, `apps/edge/internal/service`, `apps/edge/cmd/edge`, `apps/node/internal/node`, `apps/node/internal/adapters`, `apps/control-plane/cmd/control-plane`, `packages/go/config`, `apps/client`, `scripts`, `agent-ops/skills/project`, `agent-test`, `agent-spec`
- 표준선(선택): 같은 package 안에서 테스트와 파일을 먼저 기계적으로 분해하고 회귀 검증을 확보한 뒤 장기 함수와 상태 전달을 구조화한다. 파일 수보다 변경 이유의 응집도와 task-local read set을 우선한다. 공유 Agent-Ops common 경계는 수정하거나 프로젝트 ratchet 대상으로 삼지 않는다.
- 기준선(2026-07-16): Git이 추적하는 Go/Dart/Shell/Python/Kotlin/Swift 중 `proto/gen/**`와 `apps/client/lib/gen/**`를 제외한 사람이 관리하는 코드·테스트는 242개, 파일 LOC 중앙값은 216줄, 500줄 이상은 54개, 1,000줄 이상은 22개이며 이 중 테스트가 14개, 운영 코드가 8개다. 루트 추적 ELF 3개는 합계 65,474,597byte(약 65.5MB)다.
- SDD 재판정 조건: 리팩터링 중 외부 API/proto/config schema, runtime routing 정책 또는 공유 Agent-Ops common 경계 변경이 필요해지면 해당 변경을 현재 범위에서 중단하고 roadmap/SDD gate를 재판정한다.
- 선행 작업: 없음
- 후속 작업: 필요하면 Epic별 split 구현 계획으로 나누되 같은 Milestone 완료 근거로 수렴한다.
- 확인 필요: 없음
