<!-- task=m-control-plane-jenkins-aligned-layout-pass/02+01_primary_views plan=0 tag=LAYOUT -->

# Plan - LAYOUT Primary Views

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

`CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션 작성은 필수다. 구현 후 검증을 실행하고 실제 변경 내용, 설계 결정, 명령 출력, 체크리스트를 채운 뒤 active 파일을 그대로 둔 상태로 리뷰 준비를 보고한다. 최종 판정, log rename, `complete.log`, archive 이동은 code-review 전용이다.

선택된 Milestone `구현 잠금 > 결정 필요` 항목 때문에 막힌 경우에만 review stub의 `사용자 리뷰 요청` 섹션을 정확한 연결 근거와 함께 채우고 멈춘다. 구현 중 사용자에게 직접 묻거나, 선택지를 제시하거나, `request_user_input`을 호출하거나, `USER_REVIEW.md`/`complete.log`를 만들지 않는다. 환경/secret/service 차단, 일반 범위 변경, 검증 evidence 공백은 사용자 리뷰 요청이 아니라 검증 결과 또는 follow-up 대상이다.

## 배경

`01_definition_shell_foundation`이 shell/header/fallback foundation을 만든 뒤, primary 운영 view 네 개를 agent-ui Target Layout Delta에 맞춰 코드로 반영한다. 현재 `overview`, `runners`, `pipelines`, `settings`는 centered list/card layout 또는 generic fallback 상태라 Jenkins-style 운영 밀도 기준과 다르다.

## 사용자 리뷰 요청 흐름

구현 중 직접 사용자에게 묻지 않는다. 선택된 Milestone의 `구현 잠금 > 결정 필요` 항목이 실구현을 차단할 때만 active review stub의 `사용자 리뷰 요청`에 기록하고, code-review가 검증 후 실제 `USER_REVIEW.md` 생성을 맡는다.

## 분석 결과

### 읽은 파일

- `agent-ops/rules/project/rules.md`
- `agent-ops/rules/common/rules-roadmap.md`
- `agent-ops/skills/common/router.md`
- `agent-ops/skills/common/plan/SKILL.md`
- `agent-ops/skills/common/sync-agent-ui/SKILL.md`
- `agent-test/local/rules.md`
- `agent-test/local/framework-smoke.md`
- `agent-roadmap/current.md`
- `agent-roadmap/phase/control-plane-product-surface/PHASE.md`
- `agent-roadmap/phase/control-plane-product-surface/milestones/control-plane-jenkins-aligned-layout-pass.md`
- `agent-ui/definition/views/overview/index.md`
- `agent-ui/definition/views/runners/index.md`
- `agent-ui/definition/views/pipelines/index.md`
- `agent-ui/definition/views/settings/index.md`
- `agent-ui/definition/components/state-panel/index.md`
- `agent-ui/definition/components/status-badge/index.md`
- `agent-ui/definition/components/record-list/index.md`
- `agent-ui/definition/components/action-feedback/index.md`
- `agent-ui/definition/components/runner-self-update-form/index.md`
- `agent-ui/definition/components/job-create-form/index.md`
- `packages/flutter/oto_console/lib/src/oto_console_contract.dart`
- `packages/flutter/oto_console/lib/src/oto_console_shell.dart`
- `packages/flutter/oto_console/lib/src/oto_console_overview.dart`
- `packages/flutter/oto_console/lib/src/oto_runners_surface.dart`
- `packages/flutter/oto_console/lib/src/oto_jobs_surface.dart`
- `apps/client/lib/src/app/oto_client_app.dart`
- `packages/flutter/oto_console/test/oto_console_test.dart`
- `apps/client/test/widget_test.dart`

### SDD 기준

선택 Milestone은 `SDD: 불필요`다. UI layout과 code sync 범위이며 API/proto/config/schema를 바꾸지 않는다.

### 테스트 환경 규칙

- `test_env`: local.
- `agent-test/local/rules.md`와 `framework-smoke.md`를 읽었다.
- Flutter package/app 변경이므로 원격 runner `/Users/toki/agent-work/oto`에서 `packages/flutter/oto_console`와 `apps/client`의 `flutter analyze`, `flutter test`가 필요하다.
- 원격 preflight에서 checkout은 접근되지만 `command -v flutter`가 실패했다. 구현자는 원격 Flutter PATH/source sync가 준비되지 않으면 해당 출력과 blocker를 review stub에 남긴다.

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

- Overview: 기존 테스트는 `Build Operations Overview`, `CORE ONLINE`, `Health`, `Readiness`를 검증한다. status-first dashboard layout은 신규/갱신 assertion 필요.
- Runners: 기존 테스트는 loading/empty/error/data, self-update validation/action state를 검증한다. row density/action panel로 바꿔도 draft guard와 feedback assertion을 유지해야 한다.
- Pipelines: 기존 테스트는 create form, job list, execution link, action states를 검증한다. compact create panel로 바꿔도 form field count와 submit guard를 유지해야 한다.
- Settings: 기존 shell fallback 테스트는 `No local preferences`, `Browser API policy`, `same-origin proxy`를 검증한다. grouped settings로 바꿔도 유지해야 한다.

### 심볼 참조

삭제/rename 예정 symbol은 없다. `OtoConsoleOverview`, `OtoRunnersSurface`, `OtoJobsSurface`, `OtoConsoleSectionSurface` public constructors는 유지한다. 호출부는 `apps/client/lib/src/app/oto_client_app.dart`와 package tests에 있다.

### 분할 판단

multi-plan output이다. 공유 task group은 `m-control-plane-jenkins-aligned-layout-pass`.

- `01_definition_shell_foundation`: predecessor. active/archive `complete.log`는 현재 missing이다. 이 plan은 directory dependency `02+01` 때문에 01 PASS 후 구현해야 한다.
- `02+01_primary_views`: 현재 plan. overview/runners/pipelines/settings만 담당한다.
- `03+01,02_execution_artifact_views`: 후속. executions/artifacts와 final view/component layout completion 담당.

### 범위 결정 근거

Executions/artifacts/log preview/action toolbar는 이 plan에서 제외한다. agent view body도 제외한다. agent-ui status `구현됨` 전환은 milestone-required completion review로 남긴다.

### 빌드 등급

`local-G06`. 네 개 view를 만지지만 Flutter widget 범위가 명확하고 기존 tests가 주요 action/state behavior를 커버한다. 원격 runner Flutter PATH 차단 가능성은 verification blocker로 분리한다.

## 구현 체크리스트

- [ ] `01_definition_shell_foundation`의 `complete.log`가 active/archive predecessor로 존재하는지 확인하고 없으면 구현하지 않고 dependency missing을 기록한다.
- [ ] `OtoConsoleOverview`를 status-first dashboard layout으로 재배치하되 `Build Operations Overview`, endpoint, health/readiness, auth reference, refresh action을 유지한다.
- [ ] `OtoRunnersSurface`를 dense runner record list와 관리 action panel 형태로 재배치하되 self-update validation, callback, success/deferred/failed feedback을 유지한다.
- [ ] `OtoJobsSurface`를 compact create panel + dense job list로 재배치하되 create guard, submit callback, execution link navigation을 유지한다.
- [ ] Settings fallback을 runtime/security/connectivity group layout으로 정리하되 기존 endpoint/detail 문자열과 no preferences state를 유지한다.
- [ ] package/app widget tests를 갱신해 empty/error/data/action state와 primary layout markers를 검증한다.
- [ ] 원격 runner preflight와 Flutter analyze/test 계약을 실행하거나, Flutter PATH/source sync 차단이면 실제 출력과 차단 사유를 review stub에 남긴다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

## 의존 관계 및 구현 순서

디렉터리명 `02+01_primary_views`의 predecessor는 `01_definition_shell_foundation` 하나다. 구현 시작 전 `agent-task/m-control-plane-jenkins-aligned-layout-pass/01_definition_shell_foundation/complete.log` 또는 같은 task group archive의 `01_*` complete log를 확인한다. 현재 작성 시점에는 missing이다.

### [LAYOUT-1] Overview Status-First Dashboard

#### 문제

[packages/flutter/oto_console/lib/src/oto_console_overview.dart](/config/workspace/oto/packages/flutter/oto_console/lib/src/oto_console_overview.dart:28)는 `Center > ConstrainedBox(maxWidth: 840) > ListView` 구조다. agent-ui `overview` Target Layout Delta는 page header, connection status, primary refresh action, controller monitor summary를 한 줄 우선순위로 정렬해야 한다.

#### 해결 방법

Header/status/refresh를 상단 context row로 통합하고, connection status grid를 endpoints보다 먼저 스캔 가능한 summary band로 올린다. 기존 private `_StatusBadge`, `_EndpointTile`, `_ConnectionGrid`는 재사용하되 배치만 바꾼다.

Before:

```dart
// oto_console_overview.dart:28
return Container(
  color: theme.backgroundColor,
  padding: const EdgeInsets.all(24),
  child: Center(
    child: ConstrainedBox(
      constraints: const BoxConstraints(maxWidth: 840),
      child: ListView(
        children: [
          LayoutBuilder(... title + badge ...),
          const SizedBox(height: 32),
          _SectionHeader(title: 'CORE API ENDPOINTS', ...),
```

After:

```dart
return _OperationalPageBody(
  theme: theme,
  children: [
    _OverviewHeader(
      title: 'Build Operations Overview',
      statusBadge: _StatusBadge(label: _statusLabel, color: statusColor),
      onRefresh: onRefresh,
    ),
    _ConnectionGrid(theme: theme, connection: connection),
    _OperationalSection(title: 'Core API endpoints', children: [...]),
    _OperationalSection(title: 'Authentication', children: [...]),
  ],
);
```

#### 수정 파일 및 체크리스트

- [ ] `packages/flutter/oto_console/lib/src/oto_console_overview.dart`: status-first layout 재배치.
- [ ] `packages/flutter/oto_console/test/oto_console_test.dart`: overview smoke 갱신.
- [ ] `apps/client/test/widget_test.dart`: host overview smoke 갱신.

#### 테스트 작성

기존 overview tests를 유지/갱신한다. `Build Operations Overview`, `CORE ONLINE`, `Health`, `Readiness`, refresh button이 있는 경우 `Refresh`가 렌더링되는지 검증한다.

#### 중간 검증

```bash
cd packages/flutter/oto_console && flutter test
```

예상: package widget tests PASS 또는 원격 Flutter blocker 기록.

### [LAYOUT-2] Runners Dense List And Action Panel

#### 문제

[packages/flutter/oto_console/lib/src/oto_runners_surface.dart](/config/workspace/oto/packages/flutter/oto_console/lib/src/oto_runners_surface.dart:46)는 centered maxWidth card layout이고, [self-update form](/config/workspace/oto/packages/flutter/oto_console/lib/src/oto_runners_surface.dart:336)은 row 내부에 항상 펼쳐진다. agent-ui는 Jenkins Nodes/Agents처럼 runner id/status/context를 먼저 스캔하고 self-update를 관리 action 영역으로 묶도록 요구한다.

#### 해결 방법

List row는 primary id/status/context/message를 dense하게 정리하고, self-update form은 row 하단 action panel로 구분한다. callback/validation 로직은 그대로 유지한다.

Before:

```dart
// oto_runners_surface.dart:222
return Container(
  padding: const EdgeInsets.all(16),
  decoration: BoxDecoration(...),
  child: Column(
    children: [
      Row(... 'ID: ${runner.runnerID}' ... _StatusBadge ...),
      if (widget.onSelfUpdateRunner != null) _buildSelfUpdateForm(...),
    ],
  ),
);
```

After:

```dart
return _RecordRow(
  title: runner.runnerID,
  subtitle: runner.alias,
  status: _StatusBadge(status: runner.status, theme: theme),
  metadata: _RunnerContext(jobID: runner.currentJobID, executionID: runner.currentExecutionID),
  message: runner.message,
  actionPanel: widget.onSelfUpdateRunner == null ? null : _buildSelfUpdateForm(...),
);
```

#### 수정 파일 및 체크리스트

- [ ] `packages/flutter/oto_console/lib/src/oto_runners_surface.dart`: dense row/action panel layout.
- [ ] `packages/flutter/oto_console/test/oto_console_test.dart`: runner data/action states 갱신.
- [ ] `apps/client/test/widget_test.dart`: client runner self-update tests 갱신.

#### 테스트 작성

기존 runner empty/error/data/self-update tests를 갱신한다. `ID: runner-1`, `ACTIVE`, current job/execution, `Self Update`, disabled/enabled `Update`, deferred/failed feedback assertion을 유지한다.

#### 중간 검증

```bash
cd apps/client && flutter test
```

예상: app runner wiring tests PASS 또는 원격 Flutter blocker 기록.

### [LAYOUT-3] Pipelines Create Panel And Dense Job Rows

#### 문제

[packages/flutter/oto_console/lib/src/oto_jobs_surface.dart](/config/workspace/oto/packages/flutter/oto_console/lib/src/oto_jobs_surface.dart:48)는 title, wide create form, card list 순서다. agent-ui는 Jenkins Dashboard/New Item flow처럼 create entry point와 job row 비교가 분리된 compact layout을 요구한다.

#### 해결 방법

Create form은 compact panel로 감싸고 list context와 시각적으로 분리한다. Job row는 name/id/state/execution link를 같은 dense anatomy로 정리한다.

Before:

```dart
// oto_jobs_surface.dart:78
if (widget.jobCreateState != null) ...[
  _buildJobCreateForm(context, theme),
  const SizedBox(height: 20),
],
Expanded(child: _buildContent(context, theme)),
```

After:

```dart
children: [
  if (widget.jobCreateState != null)
    _CreatePanel(child: _buildJobCreateForm(context, theme)),
  Expanded(child: _buildContent(context, theme)),
]
```

#### 수정 파일 및 체크리스트

- [ ] `packages/flutter/oto_console/lib/src/oto_jobs_surface.dart`: create panel/list row layout.
- [ ] `packages/flutter/oto_console/test/oto_console_test.dart`: jobs surface tests 갱신.
- [ ] `apps/client/test/widget_test.dart`: job create and pipeline navigation tests 갱신.

#### 테스트 작성

기존 create action tests를 유지한다. `Create New Job`, 두 `TextField`, disabled/enabled `Create`, success/failed feedback, `Execution: <id>` tap callback을 검증한다.

#### 중간 검증

```bash
cd packages/flutter/oto_console && flutter test
```

예상: package jobs tests PASS 또는 원격 Flutter blocker 기록.

### [LAYOUT-4] Settings Runtime Groups

#### 문제

[packages/flutter/oto_console/lib/src/oto_console_shell.dart](/config/workspace/oto/packages/flutter/oto_console/lib/src/oto_console_shell.dart:120)는 settings override가 없으면 generic `OtoConsoleSectionSurface`에 `No local preferences`와 detail rows를 넣는다. agent-ui `settings`는 Manage Jenkins-style runtime/security/connectivity grouping을 요구한다.

#### 해결 방법

`OtoConsoleSectionSurface` detail-present variant를 group heading + detail rows로 재배치한다. Settings fallback은 HTTP API/Wire URL/Browser API policy를 group label 아래에 표시한다.

Before:

```dart
// oto_console_shell.dart:120
OtoConsoleSectionSurface(
  icon: Icons.tune,
  title: 'Settings',
  emptyTitle: 'No local preferences',
  emptyMessage: 'Settings are using runtime defaults.',
  details: [...],
)
```

After:

```dart
OtoConsoleSectionSurface(
  icon: Icons.tune,
  title: 'Settings',
  emptyTitle: 'No local preferences',
  emptyMessage: 'Settings are using runtime defaults.',
  detailGroups: [
    OtoConsoleSectionDetailGroup(title: 'Runtime endpoints', details: [...]),
    OtoConsoleSectionDetailGroup(title: 'Browser policy', details: [...]),
  ],
)
```

Public API를 새로 노출하지 않는 private/internal 구조로 구현한다. 기존 `details` constructor는 유지한다.

#### 수정 파일 및 체크리스트

- [ ] `packages/flutter/oto_console/lib/src/oto_console_shell.dart`: grouped detail variant.
- [ ] `packages/flutter/oto_console/test/oto_console_test.dart`: settings fallback assertion 갱신.
- [ ] `apps/client/test/widget_test.dart`: settings navigation smoke 갱신.

#### 테스트 작성

Settings tab 이동 후 `No local preferences`, `HTTP API`, `Wire URL`, `Browser API policy`, `same-origin proxy`를 검증한다.

#### 중간 검증

```bash
cd apps/client && flutter test
```

예상: settings host smoke PASS 또는 원격 Flutter blocker 기록.

## 수정 파일 요약

| 파일 | 항목 |
|------|------|
| `packages/flutter/oto_console/lib/src/oto_console_overview.dart` | LAYOUT-1 |
| `packages/flutter/oto_console/lib/src/oto_runners_surface.dart` | LAYOUT-2 |
| `packages/flutter/oto_console/lib/src/oto_jobs_surface.dart` | LAYOUT-3 |
| `packages/flutter/oto_console/lib/src/oto_console_shell.dart` | LAYOUT-4 |
| `packages/flutter/oto_console/test/oto_console_test.dart` | LAYOUT-1, LAYOUT-2, LAYOUT-3, LAYOUT-4 |
| `apps/client/test/widget_test.dart` | LAYOUT-1, LAYOUT-2, LAYOUT-3, LAYOUT-4 |

## 최종 검증

```bash
git diff --check
```

예상: PASS.

```bash
ssh -o BatchMode=yes -o ConnectTimeout=10 toki@toki-labs.com 'cd /Users/toki/agent-work/oto && printf "workdir=%s\n" "$PWD" && printf "branch=" && git rev-parse --abbrev-ref HEAD && printf "head=" && git rev-parse --short HEAD && printf "status-start\n" && git status --short && printf "status-end\n" && command -v flutter && flutter --version | head -n 1'
```

예상: 원격 runner Flutter 경로와 source sync 상태 확인. 현재 사전 확인에서는 Flutter PATH 실패 상태다.

```bash
ssh -o BatchMode=yes -o ConnectTimeout=10 toki@toki-labs.com 'cd /Users/toki/agent-work/oto/packages/flutter/oto_console && flutter analyze && flutter test'
```

예상: 원격 runner Flutter 준비 및 source sync 후 PASS.

```bash
ssh -o BatchMode=yes -o ConnectTimeout=10 toki@toki-labs.com 'cd /Users/toki/agent-work/oto/apps/client && flutter analyze && flutter test'
```

예상: 원격 runner Flutter 준비 및 source sync 후 PASS.

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