<!-- task=m-bridge-boundary-hardening/02_terminal_core_boundary plan=0 tag=REFACTOR -->

# Plan - REFACTOR

## 이 파일을 읽는 구현 에이전트에게

이 작업은 구현 후 active 파일을 유지하고, 반드시 `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 실제 변경 내용과 검증 출력으로 채운 뒤 리뷰 준비 상태로 멈춘다. 구현 중 사용자 결정, 사용자 소유 외부 환경, 또는 계획 범위 충돌 없이는 진행할 수 없으면 review stub의 `사용자 리뷰 요청` 섹션에 근거를 남기고 중단한다. 구현 중 사용자에게 직접 질문하거나 `USER_REVIEW.md`, `complete.log`, archive log를 만들지 않는다.

## 배경

Milestone의 `terminal-core-boundary` Task는 persistent PTY 기반 terminal core가 provider-specific CLI 구현 세부에 갇히지 않도록 Node terminal boundary를 고정하는 작업이다. 현재 `terminalSessionCore`는 `apps/node/internal/adapters/cli` 내부 private 타입이고, 출력 타입도 `cliOutput`에 묶여 있다. remote terminal bridge POC 전에 이 core를 Node 내부 재사용 경계로 옮기거나 명시 interface로 고정해야 한다.

## 사용자 리뷰 요청 흐름

구현 중 차단은 active review stub의 `사용자 리뷰 요청` 섹션에 기록한다. 직접 사용자 프롬프트는 금지하며, code-review가 요청 타당성을 검증하고 실제 `USER_REVIEW.md` 생성을 소유한다.

## Roadmap Targets

- Milestone: `agent-roadmap/phase/automation-runtime-bridge/milestones/bridge-boundary-hardening.md`
- Task ids:
  - `terminal-core-boundary`: persistent PTY 기반 `terminalSessionCore`를 CLI provider 내부 세부가 아니라 remote terminal transport가 재사용할 수 있는 Node terminal boundary로 분리하거나 명시 interface로 고정한다.
- Completion mode: check-on-pass

## 분석 결과

### 읽은 파일

- `agent-roadmap/current.md`
- `agent-roadmap/phase/automation-runtime-bridge/PHASE.md`
- `agent-roadmap/phase/automation-runtime-bridge/milestones/bridge-boundary-hardening.md`
- `agent-test/local/rules.md`
- `agent-test/local/node-smoke.md`
- `agent-test/local/testing-smoke.md`
- `agent-ops/rules/project/domain/node/rules.md`
- `agent-ops/rules/project/domain/testing/rules.md`
- `go.mod`
- `apps/node/internal/adapters/cli/cli.go`
- `apps/node/internal/adapters/cli/persistent.go`
- `apps/node/internal/adapters/cli/terminal_session.go`
- `apps/node/internal/adapters/cli/terminal_session_test.go`
- `apps/node/internal/adapters/cli/persistent_execute_blackbox_test.go`
- `apps/node/internal/adapters/cli/status/tail_buffer.go`
- `apps/node/internal/runtime/types.go`

### 테스트 환경 규칙

- test_env: `local`.
- `agent-test/local/rules.md`를 읽었고, domain routing에 따라 `node-smoke`, 사용자 실행 파이프라인 영향 기준으로 `testing-smoke`를 읽었다.
- 적용 명령: `go test -count=1 ./apps/node/internal/adapters/cli ./apps/node/internal/...`.
- 사전 확인 결과: 위 명령은 현재 checkout에서 성공했다.
- PTY/terminal 동작은 환경 민감도가 있으므로 실패 시 `command -v sh`, PTY 지원 skip 여부, 실제 stdout/stderr를 review stub에 기록한다.

### 테스트 커버리지 공백

- `terminal_session_test.go`가 prompt write, snapshot, resize, close/idempotency, write/signal after close를 검증한다.
- `persistent_execute_blackbox_test.go`가 terminal persistent execution, prompt replay, cancel, marker, raw chunk, wide PTY를 검증한다.
- 현재 공백: core가 private CLI 타입(`cliOutput`, `status.Snapshot`)에 묶여 있어 package boundary 자체를 테스트하지 못한다. 새 boundary package test를 추가해 CLI와 무관한 core contract를 검증한다.

### 심볼 참조

- 변경 예정: `terminalSessionCore`, `terminalSessionOptions`, `startTerminalSessionCore`, `cliOutput`, `status.Snapshot`.
- 현재 참조: `apps/node/internal/adapters/cli/terminal_session.go`, `apps/node/internal/adapters/cli/persistent.go`, `apps/node/internal/adapters/cli/cli.go`, `apps/node/internal/adapters/cli/terminal_session_test.go`.

### 분할 판단

- split decision policy를 적용했다.
- 공유 task group: `m-bridge-boundary-hardening`.
- sibling subtasks:
  - `01_edge_run_surface`: Edge run surface. 독립.
  - `02_terminal_core_boundary`: Node terminal package/interface boundary. 독립.
  - `03_adapter_config_typed`: typed adapter config contract. 독립.
- 이 subtask는 다른 sibling의 `complete.log`를 필요로 하지 않는다.

### 범위 결정 근거

- remote terminal bridge open/input/output/resize/signal/close protocol은 구현하지 않는다.
- SSH/WinRM/serial transport는 범위 제외다.
- CLI provider별 filtering, Claude screen parsing, opencode/codex/antigravity session state는 이번 변경에서 동작 변경 없이 call site 조정만 한다.

### 빌드 등급

- `cloud-G07`: PTY/process control과 terminal-agent behavior가 중심이며, package boundary 이동 중 미묘한 session lifecycle 회귀가 hard-to-review일 수 있다.

## 구현 체크리스트

- [ ] PTY terminal core를 `apps/node/internal/terminal` 또는 동등 Node-owned boundary로 분리하고 `terminal-core-boundary` 검증 명령을 통과시킨다.
- [ ] CLI persistent executor가 새 boundary를 소비하도록 바꾸되 provider별 filtering/session behavior를 변경하지 않는다.
- [ ] 사용자 실행 파이프라인 영향에 대해 보조 smoke/full-cycle 수행 여부 또는 생략 사유를 검증 결과에 기록한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

### [REFACTOR-1] Extract Node-Owned Terminal Core Boundary

문제: PTY core가 CLI adapter private 타입으로 갇혀 있어 remote terminal transport가 재사용할 수 없다.

Before:

```go
// apps/node/internal/adapters/cli/terminal_session.go:23
type terminalSessionCore struct {
	cmd      *exec.Cmd
	input    io.WriteCloser
	output   io.ReadCloser
	tail     *status.TailBuffer
	outputCh chan cliOutput
	doneCh   chan error
	closed   bool
	mu       sync.Mutex
}
```

```go
// apps/node/internal/adapters/cli/persistent.go:345
if profile.Terminal {
	opts := terminalSessionOptions{
		Command: profile.Command,
		Args:    profile.Args,
		Env:     profile.Env,
	}
	core, err := startTerminalSessionCore(context.Background(), opts)
```

해결 방법: `apps/node/internal/terminal` package를 만들고 `Session`, `Options`, `Output`, `Snapshot` 타입과 `StartSession(ctx, opts)`를 정의한다. `terminal.Session`은 `Output() <-chan terminal.Output`, `Done() <-chan error`, `WritePrompt`, `WriteInput`, `Resize`, `Signal`, `Snapshot`, `Close`를 제공한다. CLI package는 `terminal.Output.Text`를 `cliOutput{text: ...}`로 어댑트하고, markerLine 없는 raw terminal semantics를 유지한다.

수정 파일 및 체크리스트:

- [ ] `apps/node/internal/terminal/session.go`: PTY core와 public Node-internal interface 구현.
- [ ] `apps/node/internal/terminal/session_test.go`: 기존 terminal core tests 이동/갱신.
- [ ] `apps/node/internal/adapters/cli/terminal_session.go`: 제거하거나 CLI adapter shim만 남긴다.
- [ ] `apps/node/internal/adapters/cli/cli.go`: `profileSession.core` 타입을 새 interface로 변경.
- [ ] `apps/node/internal/adapters/cli/persistent.go`: `StartSession` 호출과 output adapter 적용.
- [ ] `apps/node/internal/adapters/cli/terminal_session_test.go`: 새 package test로 이동하거나 CLI-specific integration만 남긴다.
- [ ] `apps/node/internal/adapters/cli/persistent_execute_blackbox_test.go`: 기존 behavior regression 유지.

테스트 작성: 새 `apps/node/internal/terminal/session_test.go`를 작성한다. 기존 CLI terminal core tests를 이동해 package boundary를 직접 검증하고, CLI persistent blackbox tests는 그대로 유지한다.

중간 검증:

```bash
go test -count=1 ./apps/node/internal/terminal ./apps/node/internal/adapters/cli
```

## 수정 파일 요약

| 파일 | 항목 |
|------|------|
| `apps/node/internal/terminal/session.go` | REFACTOR-1 |
| `apps/node/internal/terminal/session_test.go` | REFACTOR-1 |
| `apps/node/internal/adapters/cli/terminal_session.go` | REFACTOR-1 |
| `apps/node/internal/adapters/cli/cli.go` | REFACTOR-1 |
| `apps/node/internal/adapters/cli/persistent.go` | REFACTOR-1 |
| `apps/node/internal/adapters/cli/terminal_session_test.go` | REFACTOR-1 |
| `apps/node/internal/adapters/cli/persistent_execute_blackbox_test.go` | REFACTOR-1 |

## 최종 검증

```bash
go test -count=1 ./apps/node/internal/adapters/cli ./apps/node/internal/...
```

예상 결과: Node internal packages가 모두 `ok`, no-test packages는 `[no test files]`.

사용자 실행 파이프라인 영향 기록: 보조 smoke/full-cycle 실제 구동을 수행했으면 명령과 출력을 붙이고, 수행하지 못했으면 `testing-smoke` 기준으로 사유와 남은 위험을 `CODE_REVIEW`에 기록한다.

모든 코드 변경 완료 후 반드시 `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 채운다. 이 파일 작성이 구현의 마지막 단계다.
