실거래 주문이 브로커에 도달하기 전에 kill switch와 계정별 주문 한도를 검증해야 한다. API, CLI, client parser surface와 완료된 review archive를 함께 정리한다.
64 lines
11 KiB
Markdown
64 lines
11 KiB
Markdown
# Headless Validation Handoff
|
|
|
|
이 문서는 `operator-headless-workflow-validation` 마일스톤의 handoff table 기준
|
|
(`agent-roadmap/phase/operator-surface/milestones/operator-headless-workflow-validation.md`)
|
|
을 충족하는 검증 evidence를 한곳에 모은다. 후속 `Flutter Operator Console MVP`는
|
|
실화면을 만들기 전에 이 matrix로 각 scenario의 command/input/expected output/exit
|
|
code/protobuf field를 확인한다.
|
|
|
|
ALT 운영 UI 게이트(`agent-ops/rules/project/rules.md`의 "운영 UI 구현 게이트")에 따라
|
|
모든 검증은 화면 없이 CLI와 machine-readable 출력으로 먼저 수행한다.
|
|
|
|
## 공통 실행 형식
|
|
|
|
- validate(offline, 소켓 없이 dry-run): `alt operator scenario validate --file <yaml>`
|
|
- run(실 API 연결): `alt operator scenario run --file <yaml> --api-url ws://127.0.0.1:18030/socket --output jsonl`
|
|
- 로컬 개발에서는 `cd apps/cli && go run ./cmd/alt <위 인자>`로 실행한다(`bin/dev` 참고).
|
|
- exit code 계약: `0` 전 step 기대 일치, `1` typed error/expectation mismatch, `2` parse/validation/flag 오류, `3` transport 실패.
|
|
- expected output fixture는 `--output jsonl` 기준의 step/summary line이다. `run_id`,
|
|
`count`, `starting_cash`, `ending_equity`, `total_return`, `trade_count`,
|
|
`error_message` 값은 seed 데이터에 따라 달라지는 illustrative 값이며, 후속 MVP가
|
|
계약으로 의존하는 부분은 line별 `scenario`/`step`/`action`/`status` key와 step별로
|
|
검증하는 protobuf field의 존재 여부다.
|
|
|
|
### command-first workflow handoff matrix
|
|
|
|
이 matrix는 import/status/backtest workflow별로 command, expected output keys,
|
|
반복 운영 여부, UI candidate/defer reason을 명시한다. 화면 레이아웃·위젯·차트는
|
|
범위 밖이며 Flutter Operator Console MVP phase에서 별도로 정의한다.
|
|
|
|
| Scenario | Command | Input fixture | Expected output fixture | Expected output keys | Expected exit code | Repeatable operation | UI candidate | Checked protobuf/view-model field | UI defer reason |
|
|
|-----|-|---|-|-|--|-|-|-|-|
|
|
| `api_connection_smoke` | `alt operator scenario run --file testdata/operator/api_connection_smoke.yaml --api-url ws://127.0.0.1:18030/socket --output jsonl` | `testdata/operator/api_connection_smoke.yaml` | `testdata/operator/expected/api_connection_smoke.jsonl` | `scenario`, `status`, `type`, `action` | `0` (성공), `3` (transport 실패 시) | yes | connection status display | `HelloResponse.capabilities`; summary `status`/`exit_code` | Flutter capability chip layout 미정 |
|
|
| `market_data_status_query` | `alt operator scenario run --file testdata/operator/market_data_status_query.yaml --api-url ws://127.0.0.1:18030/socket --output jsonl` | `testdata/operator/market_data_status_query.yaml` | `testdata/operator/expected/market_data_status_query.jsonl` | `scenario`, `status`, `type`, `action`, `provider`, `instrument_count`, `bar_count`, `count` | `0` (성공/empty), `1` (mismatch) | yes | market data status card (종목수·바개수) | `import_daily_bars` → `ImportDailyBarsResponse.instrument_count`/`bar_count`; `ListInstrumentsResponse.instruments`, `ListBarsResponse.bars`; `ErrorInfo.code` | 차트/바 시각화 레이아웃 미정 |
|
|
| `us_market_data_status_query` | `alt operator scenario run --file testdata/operator/us_market_data_status_query.yaml --api-url ws://127.0.0.1:18030/socket --output jsonl` | `testdata/operator/us_market_data_status_query.yaml` | `testdata/operator/expected/us_market_data_status_query.jsonl` | `scenario`, `status`, `type`, `action`, `provider`, `instrument_count`, `bar_count`, `count` | `0` (성공/empty), `1` (mismatch) | yes | market data status card (종목수·바개수) | `import_daily_bars` → `ImportDailyBarsResponse.instrument_count`/`bar_count`; `ListInstrumentsResponse.instruments`, `ListBarsResponse.bars`; `ErrorInfo.code` | 차트/바 시각화 레이아웃 미정 |
|
|
| `backtest_run_request` | `alt operator scenario run --file testdata/operator/backtest_run_request.yaml --api-url ws://127.0.0.1:18030/socket --output jsonl` | `testdata/operator/backtest_run_request.yaml` | `testdata/operator/expected/backtest_run_request.jsonl` | `scenario`, `status`, `type`, `action`, `run_id`, `run_status` | `0` (성공), `1` (typed error/mismatch) | yes | backtest 생성 form (parameter 입력/검증) | `StartBacktestResponse.run.id`, `BacktestRun.status` | form validation layout 미정 |
|
|
| `backtest_run_polling` | `alt operator scenario run --file testdata/operator/backtest_run_polling.yaml --api-url ws://127.0.0.1:18030/socket --output jsonl` | `testdata/operator/backtest_run_polling.yaml` | `testdata/operator/expected/backtest_run_polling.jsonl` | `scenario`, `status`, `type`, `action`, `run_id`, `run_status` | `0` (terminal 도달), `3` (polling timeout) | yes | backtest 진행 상태 표시 (상태 칩/진행바) | `GetBacktestRunResponse.run.status` 전이 (pending→running→succeeded/failed/canceled) | 진행바/상태 전이 애니메이션 미정 |
|
|
| `backtest_result_summary` | `alt operator scenario run --file testdata/operator/backtest_result_summary.yaml --api-url ws://127.0.0.1:18030/socket --output jsonl` | `testdata/operator/backtest_result_summary.yaml` | `testdata/operator/expected/backtest_result_summary.jsonl` | `scenario`, `status`, `type`, `action`, `run_id`, `starting_cash`, `ending_equity`, `total_return`, `trade_count` | `0` (성공), `1` (missing run/typed error) | yes | backtest 결과 요약 (metrics chips) | `GetBacktestResultResponse.result.summary` | 차트/메트릭 레이아웃 미정 |
|
|
| `invalid_request_matrix` | `alt operator scenario run --file testdata/operator/invalid_request_matrix.yaml --api-url ws://127.0.0.1:18030/socket --output jsonl` | `testdata/operator/invalid_request_matrix.yaml` | `testdata/operator/expected/invalid_request_matrix.jsonl` | `scenario`, `status`, `type`, `action`, `error_code`, `error_message` | `0` (기대한 typed error 도달), `2` (malformed scenario) | no (개발/검증 전용) | error/message 노출 (검증용) | `ErrorInfo.code` (`invalid_request`, `not_found`) | error 메시지 UI 미정 |
|
|
| `kis_daily_import_smoke` | `alt operator scenario run --file testdata/operator/kis_daily_import_smoke.yaml --api-url ws://127.0.0.1:18030/socket --output jsonl` | `testdata/operator/kis_daily_import_smoke.yaml` | `testdata/operator/expected/kis_daily_import_smoke.jsonl` | `scenario`, `status`, `type`, `action`, `provider`, `instrument_count`, `bar_count` | `0` (성공), `1` (mismatch/typed error) | yes | KIS import status (진행률/결과) | `ImportDailyBarsResponse.provider`, `instrument_count`, `bar_count` | import 진행 UI 미정 |
|
|
| `paper_trading_state` | `alt operator scenario run --file testdata/operator/paper_trading_state.yaml --api-url ws://127.0.0.1:18030/socket --output jsonl` | `testdata/operator/paper_trading_state.yaml` | `testdata/operator/expected/paper_trading_state.jsonl` | `scenario`, `status`, `type`, `action`, `account_id`, `run_id`, `run_status`, `cash`, `equity_point_count`, `fill_count`, `latest_equity`, `position_count`, `risk` | `0` (성공/terminal 도착), `1` (typed error/mismatch) | yes | paper trading dashboard (account 상태/포지션/평가금액/리스크) | `StartPaperTradingResponse.run.id`, `run_status`; `GetPaperTradingStateResponse.account_id`, `cash`, `equity_point_count`, `fill_count`, `latest_equity`, `position_count`, `risk_rejections`; summary `status`/`exit_code` | Flutter dashboard 레이아웃 미정 |
|
|
| `paper_order_lifecycle` | `alt operator scenario run --file testdata/operator/paper_order_lifecycle.yaml --api-url ws://127.0.0.1:18030/socket --output jsonl` | `testdata/operator/paper_order_lifecycle.yaml` | `testdata/operator/expected/paper_order_lifecycle.jsonl` | `scenario`, `status`, `type`, `action`, `account_id`, `run_id`, `run_status`, `cash`, `equity_point_count`, `fill_count`, `latest_equity`, `position_count`, `risk`, `order_id`, `order_status`, `fill_price` | `0` (성공/terminal 도착), `1` (typed error/mismatch) | yes | paper order management list (주문 상태/체결가/취소) | `StartPaperTradingResponse.run.id`, `run_status`; `SubmitPaperOrderResponse.order.id`, `order_status`; `FillPaperOrderResponse.fill_price`, `order_status`; `CancelPaperOrderResponse.order_status`; `GetPaperTradingStateResponse.account_id`, `cash`, `fill_count`; summary `status`/`exit_code` | Flutter 주문 목록/상세 레이아웃 미정 |
|
|
| `live_order_lifecycle` | `alt operator scenario run --file testdata/operator/live_order_lifecycle.yaml --api-url ws://127.0.0.1:18030/socket --output jsonl` | `testdata/operator/live_order_lifecycle.yaml` | `testdata/operator/expected/live_order_lifecycle.jsonl` | `scenario`, `status`, `type`, `action`, `live_order_id`, `live_order_status`, `broker_order_id`, `broker_status`, `operator_confirmed` | `0` (성공/operator gate 통과), `1` (typed error/confirmation missing/mismatch) | yes | live order management (실주문 상태/취소/브로커 상태) | `SubmitLiveOrderResponse.order.id`, `order.status`, `order.broker_id`, `order.broker_status`; `OperatorConfirmation.confirmed`; `CancelLiveOrderResponse.order.status`; `GetLiveOrderResponse.order.status`; summary `status`/`exit_code` | Flutter 실주문 목록/상세 레이아웃 미정 |
|
|
| `live_risk_kill_switch` | `alt operator scenario run --file testdata/operator/live_risk_kill_switch.yaml --api-url ws://127.0.0.1:18030/socket --output jsonl` | `testdata/operator/live_risk_kill_switch.yaml` | `testdata/operator/expected/live_risk_kill_switch.jsonl` | `scenario`, `status`, `type`, `action`, `max_daily_orders`, `max_open_orders`, `allow_short_selling`, `kill_switch_halted`, `kill_switch_reason` | `0` (성공/정책 조회·킬스위치 해제), `1` (typed error/mismatch) | yes | live risk 제어 패널 (정책 표시·킬스위치 토글) | `GetLiveRiskPolicyResponse.policy.max_daily_orders`, `max_open_orders`, `allow_short_selling`; `GetLiveKillSwitchResponse.state.halted`, `state.reason`; `SetLiveKillSwitchResponse.state.halted`, `state.reason`; summary `status`/`exit_code` | Flutter 킬스위치 토글·정책 표시 레이아웃 미정 |
|
|
|
|
## Exit code 계약 보강 노트
|
|
|
|
- `invalid_request_matrix.yaml`은 typed error가 "도착하는지"를 검증하므로, 의도한
|
|
error code가 오면 step은 통과하고 run은 exit `0`으로 끝난다. 이는 API가 올바른
|
|
typed `ErrorInfo`를 돌려준다는 evidence다.
|
|
- 잘못된 fixture 자체(필수 step id 누락 등)의 non-zero exit는
|
|
`testdata/operator/malformed_scenario.yaml`을 `alt operator scenario validate`로
|
|
돌리면 exit code `2`로 재현된다.
|
|
|
|
## 남은 wireframe 의존성 요약
|
|
|
|
마일스톤 비범위(out-of-scope) 항목과 직접 연결된다:
|
|
|
|
- Flutter 실화면 구현 및 dashboard layout/navigation/card/chart/form 시각 디자인 확정.
|
|
- 위 matrix의 scenario별 "UI defer reason" 열에 적힌 화면 정의.
|
|
- push notification, production 운영 자동화는 이번 마일스톤 handoff 범위 밖이다.
|
|
|
|
이 화면 정의는 `Flutter Operator Console UX Plan` / `Flutter Operator Console MVP`에서
|
|
wireframe 또는 동등한 화면 정의 산출물과 사용자 승인 기준이 준비되어야 구현 잠금이
|
|
풀린다(운영 UI 구현 게이트).
|