실거래 경계를 열기 위한 domain, contract, API, worker, client parser 등록을 함께 추가한다. 브로커 capability 조회와 live trading capability 광고가 각 런타임에서 일관되게 검증되도록 테스트와 review artifact를 포함한다.
18 KiB
Plan - LIVE_AUDIT
이 파일을 읽는 구현 에이전트에게
CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 채우는 것은 필수다. 구현 후 검증을 실행하고 실제 변경 내용, 설계 결정, 명령 출력(stdout/stderr)을 기록한 뒤 active 파일을 그대로 두고 리뷰 준비를 보고한다. 최종 판정, 로그 rename, complete.log, archive 이동은 code-review 전용이다.
구현 중 사용자만 결정할 수 있는 사항, 사용자 소유 외부 환경/secret, 또는 계획 범위 충돌 없이는 안전하게 진행할 수 없으면 active review stub의 사용자 리뷰 요청 섹션에 정확한 결정, 근거, 실행 명령/출력, 재개 조건을 기록하고 중단한다. 구현 에이전트는 사용자에게 직접 묻거나 선택지를 제시하거나 request_user_input을 호출하지 않는다. 후속 에이전트가 명령 재실행이나 산출물 수집으로 해소할 수 있는 검증 증거 공백은 사용자 리뷰 요청이 아니다.
배경
Live order, risk, account sync가 생긴 뒤에는 operator confirmation, risk decision, broker response, account sync를 재현 가능한 audit trail로 남겨야 한다. 기존 worker storage는 market/backtest 중심이고 services/worker/internal/storage/ports.go:16부터 instrument/bar/backtest ports만 있다. 이 계획은 live operation audit trail을 durable PostgreSQL storage와 headless query surface로 추가한다.
사용자 리뷰 요청 흐름
구현 중 차단은 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:
audit-trail: live operation audit trail이 있다.
- 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/rules/project/domain/operations/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.mdagent-test/local/operations-smoke.mdpackages/domain/backtest/types.gopackages/domain/market/types.gopackages/contracts/proto/alt/v1/paper_trading.protobin/contracts-genbin/contracts-checkbin/worker-storage-genbin/worker-storage-checkbin/testbin/lintservices/worker/internal/storage/ports.goservices/worker/internal/storage/postgres/store.goservices/worker/internal/storage/postgres/mapping.goservices/worker/internal/storage/postgres/mapping_test.goservices/worker/internal/storage/postgres/migrate.goservices/worker/internal/storage/postgres/migrate_test.goservices/worker/internal/storage/postgres/store_test.goservices/worker/internal/storage/postgres/queries/queries.sqlservices/worker/internal/storage/postgres/migrations/000001_worker_backbone.up.sqlservices/worker/internal/storage/postgres/migrations/000002_backtest_analysis_results.up.sqlservices/worker/internal/storage/postgres/migrations/000003_instrument_asset_type.up.sqlservices/worker/internal/storage/postgres/migrations/000003_instrument_asset_type.down.sqlservices/worker/sqlc.yamlservices/worker/internal/socket/backtest.goservices/worker/internal/socket/handlers.goservices/worker/internal/socket/paper.goservices/worker/internal/socket/paper_test.goservices/api/internal/workerclient/client.goservices/api/internal/socket/handlers.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/client.goapps/cli/internal/operator/client_test.goapps/cli/internal/operator/output.goapps/cli/testdata/operator/headless_validation.md
테스트 환경 규칙
test_env=local이다. contracts/worker/api/client/operations smoke profile을 적용한다. Storage migration/SQL query behavior가 바뀌므로 bin/worker-storage-check 실행 결과 또는 차단 사유가 필수다. .proto가 바뀌면 bin/contracts-gen, bin/contracts-check, go test ./packages/contracts/gen/go/..., bin/lint를 실행한다. Worker/API/CLI tests는 각각 go test ./services/worker/..., go test ./services/api/..., go test ./apps/cli/...다.
테스트 커버리지 공백
- Durable live audit storage: 기존 store ports와 migrations에는 live audit table/query가 없다.
- Event emission: 기존 paper/live boundary는 audit writer가 없다. Submit/cancel/risk/account sync event tests가 필요하다.
- Audit query API/CLI: 기존 CLI handoff matrix에는 live audit row가 없다.
- Secret/raw payload safety: audit payload가 raw token, account number, provider raw response를 저장하지 않는지 테스트가 필요하다.
심볼 참조
Renamed/removed symbols: none. 새 storage interfaces, sqlc queries, live audit messages/actions만 추가한다.
분할 판단
공통 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 02, 03, 04가 필요하다. 현재 active completion logs는 없으므로 구현 시작 전 order lifecycle, risk/kill switch, account sync PASS가 필요하다.
범위 결정 근거
이 subtask는 live order/risk/account behavior 자체를 새로 설계하지 않고, 완료된 predecessor의 events를 기록하고 조회한다. KIS network order/account adapter 구현은 제외한다. Audit payload는 sanitized JSON만 허용하며 raw secrets, raw tokens, raw account numbers, provider raw bodies는 저장하지 않는다.
빌드 등급
Build lane cloud-G07, review lane cloud-G07. Storage migration, sqlc generated output, protocol/API/CLI query surface, security-sensitive audit payload boundary가 함께 있어 cloud review가 필요하다.
의존 관계 및 구현 순서
Directory dependency source of truth: 05+02,03,04_audit_trail means predecessor indices 02, 03, 04. 02+01_order_lifecycle, 03+01,02_risk_kill_switch, 04+01_account_sync의 complete.log가 생긴 뒤 구현한다.
구현 체크리스트
- [LIVE_AUDIT-1] live audit domain/contract event shape를 확장한다.
- [LIVE_AUDIT-2] storage port, migration, sqlc query, postgres store를 추가한다.
- [LIVE_AUDIT-3] worker live operations에 audit writer와 query handler를 연결한다.
- [LIVE_AUDIT-4] API/CLI audit query workflow와 fixtures를 추가한다.
- [LIVE_AUDIT-5] storage/generated/focused verification을 실행한다.
- CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.
[LIVE_AUDIT-1] Audit Event Shape
문제
packages/contracts/proto/alt/v1/paper_trading.proto는 paper state/order response만 있고 operator confirmation, risk decision, broker response, account sync event를 시간순으로 조회할 audit event가 없다.
해결 방법
packages/domain/trading에 AuditEvent와 AuditEventType을 확장한다. live_trading.proto에 LiveAuditEvent, ListLiveAuditEventsRequest/Response를 추가한다. Payload는 map<string,string> 또는 sanitized JSON string 중 하나로 정하되, raw provider body를 저장하지 않는다는 테스트를 추가한다.
Before:
// services/worker/internal/storage/ports.go:45
type BacktestAnalysisStore interface {
ListRuns(ctx context.Context, status backtest.RunStatus) ([]backtest.Run, error)
GetRunDetail(ctx context.Context, id backtest.RunID) (RunDetail, error)
CompareResults(ctx context.Context, ids []backtest.RunID) ([]backtest.Result, error)
}
After:
type LiveAuditStore interface {
AppendLiveAuditEvent(ctx context.Context, event trading.AuditEvent) error
ListLiveAuditEvents(ctx context.Context, filter trading.AuditFilter) ([]trading.AuditEvent, error)
}
수정 파일 및 체크리스트
packages/domain/trading/audit.go와audit_test.go를 추가한다.packages/contracts/proto/alt/v1/live_trading.proto를 확장한다.bin/contracts-gen/generated output을 갱신한다.- parser maps에 audit messages를 등록한다.
테스트 작성
작성한다. Event type stability, sanitized payload, filter defaults를 검증한다.
중간 검증
bin/contracts-gen
bin/contracts-check
go test ./packages/domain/... ./packages/contracts/gen/go/...
기대 결과: exit code 0.
[LIVE_AUDIT-2] Storage
문제
현재 migrations는 instrument/bar/backtest tables만 만든다(000001_worker_backbone.up.sql:1, :23, :35). queries.sql:1부터 instrument/backtest queries만 있고 live audit query가 없다. ports.go:16부터 storage interface에도 audit store가 없다.
해결 방법
000004_live_audit_events.up.sql과 .down.sql을 추가한다. Table은 event_id, account_id, broker, order_id, event_type, status, reason, actor, correlation_id, payload, created_at를 갖고 account/order/time index를 둔다. queries.sql에 append/list queries를 추가하고 bin/worker-storage-gen으로 sqlc output을 갱신한다. Store가 storage.LiveAuditStore를 구현한다.
수정 파일 및 체크리스트
services/worker/internal/storage/ports.go에LiveAuditStore를 추가한다.services/worker/internal/storage/postgres/migrations/000004_live_audit_events.up.sql을 추가한다.services/worker/internal/storage/postgres/migrations/000004_live_audit_events.down.sql을 추가한다.services/worker/internal/storage/postgres/queries/queries.sql에 audit queries를 추가한다.services/worker/internal/storage/postgres/mapping.go에 audit mapping을 추가한다.services/worker/internal/storage/postgres/store.go에 append/list methods를 추가한다.services/worker/internal/storage/postgres/sqlc/**는bin/worker-storage-gen으로만 갱신한다.
테스트 작성
작성한다. migrate_test.go에 000004 up/down pairing과 table columns check를 추가한다. mapping_test.go에 audit mapping round trip과 raw secret key rejection을 추가한다. store_test.go에 append/list order/filter integration test를 추가한다.
중간 검증
bin/worker-storage-gen
bin/worker-storage-check
go test ./services/worker/internal/storage/...
기대 결과: exit code 0. PostgreSQL-backed tests skip 조건은 기존 store_test.go:27의 DATABASE_URL 기준을 따른다. bin/worker-storage-check 실행 불가 시 pass가 아니며 사유를 기록한다.
[LIVE_AUDIT-3] Worker Emission And Query
문제
Live order/risk/account services가 operation event를 기록할 writer dependency가 없다. Audit query handler도 없다.
해결 방법
livetrading.Service에 optional AuditStore 또는 AuditWriter를 주입한다. Submit confirmation, broker accepted/rejected, cancel, risk blocked, kill switch set, account sync success/failure에 audit event를 append한다. Append failure는 operation response에 internal error로 반영할지, operation success와 audit failure를 분리할지 명확히 정한다. 이 boundary milestone에서는 audit trail 필수성을 위해 append failure는 typed internal error로 처리한다.
수정 파일 및 체크리스트
services/worker/internal/livetrading/service.go에 audit writer를 연결한다.services/worker/internal/livetrading/service_test.go에 event emission tests를 추가한다.services/worker/internal/socket/live.go에ListLiveAuditEventshandler를 추가한다.services/worker/internal/socket/live_mapping.go에 audit proto mapping을 추가한다.services/worker/internal/socket/live_test.go에 audit query tests를 추가한다.
테스트 작성
작성한다. Submit, risk blocked, cancel, account sync event가 expected order로 append되는지, audit writer failure가 internal error로 매핑되는지 검증한다.
중간 검증
go test ./services/worker/internal/livetrading ./services/worker/internal/socket
기대 결과: exit code 0.
[LIVE_AUDIT-4] API And CLI Query
문제
Operator가 audit trail을 headless로 조회할 API/CLI surface가 없다.
해결 방법
API workerclient와 socket handler에 ListLiveAuditEvents forwarder를 추가한다. CLI에는 list_live_audit_events action을 추가하고 output에 audit_count, audit_event_id, audit_event_type, audit_order_id, audit_status, audit_reason을 render한다. apps/cli/testdata/operator/live_audit_trail.yaml과 expected JSONL을 추가하고 handoff matrix에 row를 추가한다.
수정 파일 및 체크리스트
services/api/internal/workerclient/client.go를 확장한다.services/api/internal/socket/live.go와 tests를 확장한다.apps/cli/internal/operator/scenario.go,runner.go,client.go,output.go를 확장한다.apps/cli/internal/operator/runner_live_test.go에 audit tests를 추가한다.apps/cli/testdata/operator/live_audit_trail.yaml과 expected JSONL을 추가한다.apps/cli/testdata/operator/headless_validation.md에 audit row를 추가한다.
테스트 작성
작성한다. CLI list success, filter by account/order, typed not_found or empty list behavior, fixture JSONL parse를 포함한다.
중간 검증
go test ./services/api/internal/socket ./apps/cli/internal/operator
기대 결과: exit code 0.
[LIVE_AUDIT-5] Verification
문제
Audit trail은 storage migration/generated drift와 cross-module proto/API/CLI drift를 동시에 일으킨다.
해결 방법
Storage, contracts, affected Go modules, generated Dart lint까지 검증한다.
수정 파일 및 체크리스트
bin/worker-storage-check를 실행한다.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를 실행한다.
테스트 작성
추가 테스트는 LIVE_AUDIT-1부터 LIVE_AUDIT-4에 포함한다.
중간 검증
bin/worker-storage-check
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. bin/worker-storage-check 또는 bin/lint를 실행할 수 없으면 pass가 아니며 command -v 근거와 미실행 사유를 기록한다.
수정 파일 요약
| 파일 | 항목 |
|---|---|
packages/domain/trading/audit.go |
LIVE_AUDIT-1 |
packages/domain/trading/audit_test.go |
LIVE_AUDIT-1 |
packages/contracts/proto/alt/v1/live_trading.proto |
LIVE_AUDIT-1 |
services/worker/internal/contracts/parser_map.go |
LIVE_AUDIT-1 |
services/api/internal/contracts/parser_map.go |
LIVE_AUDIT-1 |
apps/cli/internal/operator/parser_map.go |
LIVE_AUDIT-1 |
services/worker/internal/storage/ports.go |
LIVE_AUDIT-2 |
services/worker/internal/storage/postgres/migrations/000004_live_audit_events.up.sql |
LIVE_AUDIT-2 |
services/worker/internal/storage/postgres/migrations/000004_live_audit_events.down.sql |
LIVE_AUDIT-2 |
services/worker/internal/storage/postgres/queries/queries.sql |
LIVE_AUDIT-2 |
services/worker/internal/storage/postgres/mapping.go |
LIVE_AUDIT-2 |
services/worker/internal/storage/postgres/mapping_test.go |
LIVE_AUDIT-2 |
services/worker/internal/storage/postgres/migrate_test.go |
LIVE_AUDIT-2 |
services/worker/internal/storage/postgres/store.go |
LIVE_AUDIT-2 |
services/worker/internal/storage/postgres/store_test.go |
LIVE_AUDIT-2 |
services/worker/internal/storage/postgres/sqlc/** |
LIVE_AUDIT-2 |
services/worker/internal/livetrading/service.go |
LIVE_AUDIT-3 |
services/worker/internal/livetrading/service_test.go |
LIVE_AUDIT-3 |
services/worker/internal/socket/live.go |
LIVE_AUDIT-3 |
services/worker/internal/socket/live_mapping.go |
LIVE_AUDIT-3 |
services/worker/internal/socket/live_test.go |
LIVE_AUDIT-3 |
services/api/internal/workerclient/client.go |
LIVE_AUDIT-4 |
services/api/internal/socket/live.go |
LIVE_AUDIT-4 |
services/api/internal/socket/live_test.go |
LIVE_AUDIT-4 |
apps/cli/internal/operator/scenario.go |
LIVE_AUDIT-4 |
apps/cli/internal/operator/runner.go |
LIVE_AUDIT-4 |
apps/cli/internal/operator/client.go |
LIVE_AUDIT-4 |
apps/cli/internal/operator/output.go |
LIVE_AUDIT-4 |
apps/cli/internal/operator/runner_live_test.go |
LIVE_AUDIT-4 |
apps/cli/testdata/operator/live_audit_trail.yaml |
LIVE_AUDIT-4 |
apps/cli/testdata/operator/expected/live_audit_trail.jsonl |
LIVE_AUDIT-4 |
apps/cli/testdata/operator/headless_validation.md |
LIVE_AUDIT-4 |
최종 검증
bin/worker-storage-check
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. bin/worker-storage-check 실행 불가 시 command -v go와 실패 stdout/stderr를 기록한다. bin/lint가 Flutter/Dart toolchain 부재로 실행 불가하면 command -v flutter 결과와 함께 차단 근거를 기록한다.
모든 코드 변경 완료 후 반드시 CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 채운다. 이 파일 작성이 구현의 마지막 단계다.