실거래 경계를 열기 위한 domain, contract, API, worker, client parser 등록을 함께 추가한다. 브로커 capability 조회와 live trading capability 광고가 각 런타임에서 일관되게 검증되도록 테스트와 review artifact를 포함한다.
14 KiB
Plan - LIVE_RISK
이 파일을 읽는 구현 에이전트에게
CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 채우는 것은 필수다. 구현 후 검증을 실행하고 실제 변경 내용, 설계 결정, 명령 출력(stdout/stderr)을 기록한 뒤 active 파일을 그대로 두고 리뷰 준비를 보고한다. 최종 판정, 로그 rename, complete.log, archive 이동은 code-review 전용이다.
구현 중 사용자만 결정할 수 있는 사항, 사용자 소유 외부 환경/secret, 또는 계획 범위 충돌 없이는 안전하게 진행할 수 없으면 active review stub의 사용자 리뷰 요청 섹션에 정확한 결정, 근거, 실행 명령/출력, 재개 조건을 기록하고 중단한다. 구현 에이전트는 사용자에게 직접 묻거나 선택지를 제시하거나 request_user_input을 호출하지 않는다. 후속 에이전트가 명령 재실행이나 산출물 수집으로 해소할 수 있는 검증 증거 공백은 사용자 리뷰 요청이 아니다.
배경
Live order lifecycle이 생긴 뒤에는 실거래 주문 제출 전 risk guard와 kill switch가 반드시 있어야 한다. 사용자는 수익률을 포기하지 말라고 결정했지만, 실거래 경계에는 손실 확대를 막는 최소 정책값과 즉시 차단 장치가 필요하다. 이 계획은 수치를 설계에 고정하지 않고 조정 가능한 기본값으로 두며, 기능 capability는 닫지 않는다.
사용자 리뷰 요청 흐름
구현 중 차단은 active CODE_REVIEW-*-G??.md의 사용자 리뷰 요청 섹션에 기록한다. 이 섹션은 agent-ops/skills/common/_templates/implementation-user-review-request-section.md 형식을 따른다. 구현 중 직접 사용자 프롬프트는 금지이며, code-review가 요청의 타당성을 검증하고 실제 USER_REVIEW.md 작성을 소유한다.
Roadmap Targets
- Milestone:
agent-roadmap/phase/trading-expansion/milestones/live-trading-boundary.md - Task ids:
risk-limits: 실거래 전 최소 risk limit과 kill switch가 있다.
- Completion mode: check-on-pass
분석 결과
읽은 파일
agent-roadmap/current.mdagent-roadmap/phase/trading-expansion/PHASE.mdagent-roadmap/phase/trading-expansion/milestones/live-trading-boundary.mdagent-ops/rules/project/rules.mdagent-ops/rules/project/domain/domain-model/rules.mdagent-ops/rules/project/domain/contracts/rules.mdagent-ops/rules/project/domain/worker/rules.mdagent-ops/rules/project/domain/api/rules.mdagent-ops/skills/common/plan/SKILL.mdagent-test/local/rules.mdagent-test/local/domain-model-smoke.mdagent-test/local/contracts-smoke.mdagent-test/local/worker-smoke.mdagent-test/local/api-smoke.mdagent-test/local/client-smoke.mdpackages/domain/backtest/types.gopackages/domain/backtest/types_test.gopackages/domain/market/types.gopackages/contracts/proto/alt/v1/paper_trading.protobin/contracts-genbin/contracts-checkservices/worker/internal/papertrading/service.goservices/worker/internal/papertrading/service_test.goservices/worker/internal/socket/backtest.goservices/worker/internal/socket/handlers.goservices/worker/internal/socket/paper.goservices/worker/internal/socket/paper_mapping.goservices/worker/internal/socket/paper_test.goservices/api/internal/workerclient/client.goservices/api/internal/socket/paper.goservices/api/internal/socket/paper_test.goapps/cli/internal/operator/scenario.goapps/cli/internal/operator/runner.goapps/cli/internal/operator/runner_paper_test.goapps/cli/internal/operator/output.go
테스트 환경 규칙
test_env=local이다. domain/contracts/worker/api/client smoke profile을 적용한다. .proto 확장이 있으면 bin/contracts-gen, bin/contracts-check, go test ./packages/contracts/gen/go/..., bin/lint를 실행한다. Worker/API/CLI 변경은 각각 go test ./services/worker/..., go test ./services/api/..., go test ./apps/cli/...로 검증한다.
테스트 커버리지 공백
- Live risk policy defaults: 기존 테스트 없음. 새 domain/worker tests가 필요하다.
- Kill switch default deny와 operator override flow: 기존 paper risk는 short selling만 막는다(
services/worker/internal/papertrading/service.go:277). live kill switch 테스트가 필요하다. - Submit path risk guard: 02의 live submit path에 risk check가 붙어야 하므로 통합 worker socket test가 필요하다.
- CLI risk/kill output: 기존 paper output은
risk=clear/blocked만 있다(apps/cli/internal/operator/output.go:52). live risk decision fields가 필요하다.
심볼 참조
Renamed/removed symbols: none. 새 risk/kill switch symbols만 추가한다.
분할 판단
공통 task group은 m-live-trading-boundary다. sibling split은 01_broker_port, 02+01_order_lifecycle, 03+01,02_risk_kill_switch, 04+01_account_sync, 05+02,03,04_audit_trail이다. 이 subtask는 predecessor 01과 02가 필요하다. 현재 active 01_broker_port/complete.log와 02+01_order_lifecycle/complete.log는 없으므로 구현 시작 전 두 predecessor PASS가 필요하다.
범위 결정 근거
이 subtask는 account sync와 durable audit을 구현하지 않는다. Risk policy 값은 기본값으로 제안하되 config/test fixture로 분리한다. 구체 주문 유형을 제한하지 않으며, risk check는 notional/quantity/order count/kill switch처럼 주문 type과 독립적인 정책을 먼저 평가한다.
빌드 등급
Build lane cloud-G06, review lane cloud-G06. 실거래 제출 차단 경계와 protocol/API/CLI 영향이 있으나 storage나 external broker network는 없다.
의존 관계 및 구현 순서
Directory dependency source of truth: 03+01,02_risk_kill_switch means predecessor indices 01 and 02. 구현은 01_broker_port와 02+01_order_lifecycle의 complete.log가 생긴 뒤 시작한다.
구현 체크리스트
- [LIVE_RISK-1] live risk policy domain/config defaults를 추가한다.
- [LIVE_RISK-2] worker submit path에 risk guard와 kill switch를 적용한다.
- [LIVE_RISK-3] risk/kill switch contract, API forwarder, CLI actions/output을 추가한다.
- [LIVE_RISK-4] focused verification과 affected module tests를 실행한다.
- CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.
[LIVE_RISK-1] Risk Policy Defaults
문제
packages/domain/backtest/types.go:395의 CheckRisk는 paper account short selling만 평가한다. Live risk는 order notional, order count, kill switch를 표현할 domain/config 경계가 없다.
해결 방법
packages/domain/trading에 RiskPolicy, RiskDecision, KillSwitchState를 추가한다. 기본값은 조정 가능한 값으로 둔다: kill switch default halted=true, max notional KRW 1000000, USD 1000, max daily orders 5, max open live orders 3, allow short selling false. 구현자가 config struct와 test fixture로 이 값을 주입하게 해서 후속 수치 조정은 코드 구조 변경 없이 가능하게 한다.
Before:
// packages/domain/backtest/types.go:395
func CheckRisk(account PaperAccount, order OrderIntent) RiskDecision {
if account.RiskSettings.AllowShortSelling {
return RiskDecision{Allowed: true, Reason: "risk check passed"}
}
After:
type RiskPolicy struct {
MaxOrderNotionalByCurrency map[market.Currency]market.Decimal
MaxDailyOrders int
MaxOpenOrders int
AllowShortSelling bool
}
type KillSwitchState struct {
Halted bool
Reason string
}
수정 파일 및 체크리스트
packages/domain/trading/types.go또는risk.go에 risk types를 추가한다.packages/domain/trading/types_test.go또는risk_test.go에 default/boundary tests를 추가한다.services/worker/internal/livetrading/config.go에 worker runtime 기본값을 둔다.
테스트 작성
작성한다. Notional below/above threshold, kill switch halted, custom order type unaffected, empty/invalid default handling을 검증한다.
중간 검증
go test ./packages/domain/...
기대 결과: exit code 0.
[LIVE_RISK-2] Worker Guard
문제
02의 live submit path는 operator confirmation 뒤 broker port를 호출한다. Risk guard가 없으면 confirmation만으로 live broker 호출이 가능해진다.
해결 방법
livetrading.Service.SubmitLiveOrder에서 operator confirmation 후, broker call 전 risk guard를 실행한다. Kill switch가 halted이면 invalid_request 또는 risk_blocked typed error로 응답하고 broker를 호출하지 않는다. Risk denial은 order status rejected 또는 blocked로 저장하고 reason을 반환한다. Error vocabulary는 기존 invalid_request, unavailable, not_found, timeout, internal을 재사용하거나 live-specific code를 contract에 추가하되 API/CLI tests와 일치시킨다.
수정 파일 및 체크리스트
services/worker/internal/livetrading/service.go에 risk evaluator를 주입한다.services/worker/internal/livetrading/service_test.go에 broker-not-called tests를 추가한다.services/worker/internal/socket/live.go에 risk error mapping을 추가한다.services/worker/internal/socket/live_test.go에 submit risk blocked tests를 추가한다.
테스트 작성
작성한다. TestSubmitLiveOrderKillSwitchBlocksBeforeBroker, TestSubmitLiveOrderMaxNotionalBlocks, TestSubmitLiveOrderRiskAllowedCallsBroker를 포함한다.
중간 검증
go test ./services/worker/internal/livetrading ./services/worker/internal/socket
기대 결과: exit code 0.
[LIVE_RISK-3] Contract/API/CLI Surface
문제
Operator가 현재 risk policy와 kill switch 상태를 조회/전환할 headless command가 없다. Live submit 실패 이유도 CLI output에 안정적으로 남지 않는다.
해결 방법
live_trading.proto에 GetLiveRiskPolicyRequest/Response, GetLiveKillSwitchRequest/Response, SetLiveKillSwitchRequest/Response, LiveRiskDecision을 추가한다. API는 thin forwarder로 구현한다. CLI는 get_live_risk_policy, get_live_kill_switch, set_live_kill_switch actions와 live submit risk output fields를 추가한다.
수정 파일 및 체크리스트
packages/contracts/proto/alt/v1/live_trading.proto를 확장한다.bin/contracts-gen/generated output을 갱신한다.- worker/API/CLI parser map에 새 messages를 등록한다.
services/api/internal/workerclient/client.go와services/api/internal/socket/live.go를 확장한다.apps/cli/internal/operator/scenario.go,runner.go,output.go,client.go를 확장한다.apps/cli/testdata/operator/live_risk_kill_switch.yaml과 expected JSONL을 추가한다.
테스트 작성
작성한다. API forwarder tests, CLI validation/output tests, fixture parse tests를 추가한다.
중간 검증
bin/contracts-gen
bin/contracts-check
go test ./services/api/internal/socket ./apps/cli/internal/operator
기대 결과: exit code 0.
[LIVE_RISK-4] Verification
문제
Risk guard는 money-moving boundary에 직접 영향을 주므로 domain/worker/API/CLI를 함께 검증해야 한다.
해결 방법
focused와 affected module tests를 실행한다.
수정 파일 및 체크리스트
bin/contracts-check를 실행한다.go test ./packages/domain/...를 실행한다.go test ./packages/contracts/gen/go/...를 실행한다.go test ./services/worker/...를 실행한다.go test ./services/api/...를 실행한다.go test ./apps/cli/...를 실행한다.
테스트 작성
추가 테스트는 LIVE_RISK-1부터 LIVE_RISK-3에 포함한다.
중간 검증
bin/contracts-check
go test ./packages/domain/...
go test ./packages/contracts/gen/go/...
go test ./services/worker/...
go test ./services/api/...
go test ./apps/cli/...
bin/lint
기대 결과: 모두 exit code 0. Go test cache output은 최종 검증에서 허용한다. Flutter/Dart toolchain 부재로 bin/lint가 실행 불가하면 pass가 아니며 차단 근거를 기록한다.
수정 파일 요약
| 파일 | 항목 |
|---|---|
packages/domain/trading/risk.go |
LIVE_RISK-1 |
packages/domain/trading/risk_test.go |
LIVE_RISK-1 |
services/worker/internal/livetrading/config.go |
LIVE_RISK-1 |
services/worker/internal/livetrading/service.go |
LIVE_RISK-2 |
services/worker/internal/livetrading/service_test.go |
LIVE_RISK-2 |
services/worker/internal/socket/live.go |
LIVE_RISK-2, LIVE_RISK-3 |
services/worker/internal/socket/live_test.go |
LIVE_RISK-2 |
packages/contracts/proto/alt/v1/live_trading.proto |
LIVE_RISK-3 |
services/worker/internal/contracts/parser_map.go |
LIVE_RISK-3 |
services/api/internal/contracts/parser_map.go |
LIVE_RISK-3 |
apps/cli/internal/operator/parser_map.go |
LIVE_RISK-3 |
services/api/internal/workerclient/client.go |
LIVE_RISK-3 |
services/api/internal/socket/live.go |
LIVE_RISK-3 |
services/api/internal/socket/live_test.go |
LIVE_RISK-3 |
apps/cli/internal/operator/scenario.go |
LIVE_RISK-3 |
apps/cli/internal/operator/runner.go |
LIVE_RISK-3 |
apps/cli/internal/operator/output.go |
LIVE_RISK-3 |
apps/cli/internal/operator/client.go |
LIVE_RISK-3 |
apps/cli/internal/operator/runner_live_test.go |
LIVE_RISK-3 |
apps/cli/testdata/operator/live_risk_kill_switch.yaml |
LIVE_RISK-3 |
apps/cli/testdata/operator/expected/live_risk_kill_switch.jsonl |
LIVE_RISK-3 |
최종 검증
bin/contracts-check
go test ./packages/domain/...
go test ./packages/contracts/gen/go/...
go test ./services/worker/...
go test ./services/api/...
go test ./apps/cli/...
bin/lint
기대 결과: 모든 명령 exit code 0.
모든 코드 변경 완료 후 반드시 CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 채운다. 이 파일 작성이 구현의 마지막 단계다.