diff --git a/agent-ops/skills/project/run-proto-socket-test-matrix/SKILL.md b/agent-ops/skills/project/run-proto-socket-test-matrix/SKILL.md index 2567888..fdd7ed1 100644 --- a/agent-ops/skills/project/run-proto-socket-test-matrix/SKILL.md +++ b/agent-ops/skills/project/run-proto-socket-test-matrix/SKILL.md @@ -193,6 +193,7 @@ tools/check_proto_sync.sh - `run_full_test.sh --dry-run` 출력이 `functional-full`, `functional-full-dart-web`, `functional-full-dart-web-wss`를 `recommended` 상태로 포함하면 full functional periodic이 발동된다. 이 dry-run은 내부에서 `run_test_by_change.sh --route full --dry-run` classifier를 호출한다. - full functional 호출 시 `run_matrix.sh --all` 또는 `--cross` 실행으로 언어 PASS 매트릭스(Dart.io, Dart.web, Dart.web(WSS), Go, Kotlin, Python, TypeScript)와 크로스테스트 상세 표를 반드시 확인한다. +- 언어 anchor 후보는 full 5x5 대신 `run_matrix.sh --cross --anchor --direction server|client|both`로 실행한다. self 방향은 해당 언어 동일언어 테스트로 채우고, Dart.web/WSS는 anchor x5에 포함하지 않는다. - Dart.web과 Dart.web(WSS)는 브라우저 client runtime이므로 서버 행에는 넣지 않는다. - Dart.web/WSS client coverage는 full matrix의 `Dart.web` 및 `Dart.web(WSS)` 열에서 각 server-capable 언어 행이 모두 `PASS`여야 한다. - `recommended`: 즉시 실행 후보. runner가 실행해야 함. @@ -227,4 +228,4 @@ tools/check_proto_sync.sh - non-dry-run 실행 시 선택 이유, 실행 명령, 결과 record 경로를 출력에 남긴다. - 실행하지 않은 skipped/nightly-pending 항목은 PASS로 보고하지 않는다. - `nightly-pending` 후보는 `## nightly-pending 후보 (미실행, PASS 아님)` 섹션에 후보 command와 함께 기록한다. -- anchor 실행(`functional-server-x5`, `functional-client-x5`, `functional-both-x5`)은 anchor-runner-options 범위로 남기고 `anchor-skipped`로 기록한다. +- anchor 실행(`functional-server-x5`, `functional-client-x5`, `functional-both-x5`)은 지원 언어 target이면 `run_matrix.sh --cross --anchor --direction `를 실행하고 결과 record를 남긴다. `transport/queue` 같은 비언어 target은 실행하지 않고 skipped로 기록한다. diff --git a/agent-ops/skills/project/run-proto-socket-test-matrix/scripts/run_matrix.sh b/agent-ops/skills/project/run-proto-socket-test-matrix/scripts/run_matrix.sh index 3d7a4c0..50947e3 100755 --- a/agent-ops/skills/project/run-proto-socket-test-matrix/scripts/run_matrix.sh +++ b/agent-ops/skills/project/run-proto-socket-test-matrix/scripts/run_matrix.sh @@ -3,23 +3,110 @@ set -u usage() { cat <<'USAGE' -Usage: run_matrix.sh [--all|--unit|--cross|--proto] +Usage: run_matrix.sh [--all|--unit|--cross|--proto] [--anchor LANG --direction server|client|both] Runs Proto Socket proto schema sync, unit/same-language tests, and/or cross-language communication tests, then prints Markdown PASS/FAIL tables. Each run also writes a local result record under agent-test/runs/. Defaults to --all. + +Anchor options: + --anchor LANG Focus cross tests around dart, go, kotlin, python, or typescript. + --direction DIR server, client, or both. Anchor mode runs the anchor same-language + test for the self cell and only the selected x5 cross directions. USAGE } +normalize_anchor_language() { + case "$1" in + dart|Dart|dart.io|Dart.io) echo "Dart" ;; + go|Go) echo "Go" ;; + kotlin|Kotlin) echo "Kotlin" ;; + python|Python) echo "Python" ;; + typescript|TypeScript|ts|TS) echo "TypeScript" ;; + *) return 1 ;; + esac +} + +language_slug() { + case "$1" in + Dart) echo "dart" ;; + Go) echo "go" ;; + Kotlin) echo "kotlin" ;; + Python) echo "python" ;; + TypeScript) echo "typescript" ;; + *) return 1 ;; + esac +} + mode="all" -case "${1:-}" in - ""|--all) mode="all" ;; - --unit) mode="unit" ;; - --cross) mode="cross" ;; - --proto) mode="proto" ;; - -h|--help) usage; exit 0 ;; - *) usage >&2; exit 2 ;; +mode_set=0 +anchor_arg="" +anchor_language="" +anchor_slug="" +direction="both" + +while [ "$#" -gt 0 ]; do + case "$1" in + --all) mode="all"; mode_set=1 ;; + --unit) mode="unit"; mode_set=1 ;; + --cross) mode="cross"; mode_set=1 ;; + --proto) mode="proto"; mode_set=1 ;; + --anchor=*) anchor_arg="${1#--anchor=}" ;; + --anchor) + shift + if [ "$#" -eq 0 ]; then + printf 'Error: --anchor requires a language\n' >&2 + usage >&2 + exit 2 + fi + anchor_arg="$1" + ;; + --direction=*) direction="${1#--direction=}" ;; + --direction) + shift + if [ "$#" -eq 0 ]; then + printf 'Error: --direction requires server, client, or both\n' >&2 + usage >&2 + exit 2 + fi + direction="$1" + ;; + -h|--help) usage; exit 0 ;; + *) usage >&2; exit 2 ;; + esac + shift +done + +if [ -n "$anchor_arg" ]; then + if ! anchor_language="$(normalize_anchor_language "$anchor_arg")"; then + printf 'Error: unknown anchor language "%s"\n' "$anchor_arg" >&2 + usage >&2 + exit 2 + fi + anchor_slug="$(language_slug "$anchor_language")" + if [ "$mode" = "all" ] && [ "$mode_set" -eq 0 ]; then + mode="cross" + elif [ "$mode" != "cross" ]; then + printf 'Error: --anchor is only supported with --cross\n' >&2 + usage >&2 + exit 2 + fi +fi + +if [ -z "$anchor_language" ] && [ "$direction" != "both" ]; then + printf 'Error: --direction requires --anchor\n' >&2 + usage >&2 + exit 2 +fi + +case "$direction" in + server|client|both) ;; + *) + printf 'Error: unknown direction "%s". Use: server, client, both\n' "$direction" >&2 + usage >&2 + exit 2 + ;; esac script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" @@ -42,12 +129,16 @@ remote_web_ref="${PROTO_SOCKET_DART_WEB_REF:-$(git -C "$repo_root" rev-parse --a remote_web_execution="local" remote_web_prepare_summary="" -case "$mode" in - all) record_profile="proto-socket-full-matrix" ;; - unit) record_profile="proto-socket-unit-matrix" ;; - cross) record_profile="proto-socket-cross-matrix" ;; - proto) record_profile="proto-socket-proto-sync" ;; -esac +if [ -n "$anchor_language" ]; then + record_profile="proto-socket-anchor-${anchor_slug}-${direction}-matrix" +else + case "$mode" in + all) record_profile="proto-socket-full-matrix" ;; + unit) record_profile="proto-socket-unit-matrix" ;; + cross) record_profile="proto-socket-cross-matrix" ;; + proto) record_profile="proto-socket-proto-sync" ;; + esac +fi languages=("Dart" "Go" "Kotlin" "Python" "TypeScript") @@ -305,24 +396,41 @@ $cmd " >"$log_file" 2>&1 } +run_unit_test_for_language() { + local lang="$1" + local cmd dir log_file status + cmd="${unit_cmds[$lang]}" + dir="${unit_dirs[$lang]}" + log_file="$log_dir/unit_${lang}.log" + run_logged "unit $lang: $cmd" "$dir" "$cmd" "$log_file" + status=$? + unit_status[$lang]="$status" + if [ "$status" -eq 0 ]; then + unit_result[$lang]="PASS" + else + unit_result[$lang]="FAIL" + fi + unit_summary[$lang]="$(tail -n 1 "$log_file" | tr '\n' ' ')" +} + run_unit_tests() { - local lang cmd dir log_file status + local lang for lang in "${languages[@]}"; do - cmd="${unit_cmds[$lang]}" - dir="${unit_dirs[$lang]}" - log_file="$log_dir/unit_${lang}.log" - run_logged "unit $lang: $cmd" "$dir" "$cmd" "$log_file" - status=$? - unit_status[$lang]="$status" - if [ "$status" -eq 0 ]; then - unit_result[$lang]="PASS" - else - unit_result[$lang]="FAIL" - fi - unit_summary[$lang]="$(tail -n 1 "$log_file" | tr '\n' ' ')" + run_unit_test_for_language "$lang" done } +should_run_cross_case() { + local server="$1" + local client="$2" + [ -z "$anchor_language" ] && return 0 + case "$direction" in + server) [ "$server" = "$anchor_language" ] ;; + client) [ "$client" = "$anchor_language" ] ;; + both) [ "$server" = "$anchor_language" ] || [ "$client" = "$anchor_language" ] ;; + esac +} + run_proto_sync() { local log_file status log_file="$log_dir/proto_sync.log" @@ -341,6 +449,7 @@ run_cross_tests() { local item server client dir cmd key log_file status pass_count fail_count for item in "${cross_cases[@]}"; do IFS='|' read -r server client dir cmd <<<"$item" + should_run_cross_case "$server" "$client" || continue key="$server|$client" log_file="$log_dir/cross_${server}_${client}.log" cross_cmds[$key]="(cd ${dir#$repo_root/} && $cmd)" @@ -467,10 +576,14 @@ print_proto_table() { print_unit_table() { local lang + local unit_languages=("${languages[@]}") + if [ -n "$anchor_language" ]; then + unit_languages=("$anchor_language") + fi printf '\n**동일언어**\n' printf '| 언어 | 명령 | 결과 |\n' printf '|---|---|---|\n' - for lang in "${languages[@]}"; do + for lang in "${unit_languages[@]}"; do printf '| %s | `%s` | %s |\n' "$lang" "${unit_cmds[$lang]}" "${unit_result[$lang]:--}" done } @@ -513,7 +626,9 @@ language_matrix_cell() { key="$server|$client" if [ "$server" = "$client" ]; then - if [ "$mode" = "all" ] || [ "$mode" = "unit" ]; then + if [ -n "${unit_result[$server]:-}" ]; then + echo "${unit_result[$server]:--}" + elif [ "$mode" = "all" ] || [ "$mode" = "unit" ]; then echo "${unit_result[$server]:--}" else echo "-" @@ -526,8 +641,28 @@ language_matrix_cell() { print_language_pass_matrix() { local server client + local server_capable=("Dart.io" "Go" "Kotlin" "Python" "TypeScript") local servers=("Dart.io" "Go" "Kotlin" "Python" "TypeScript") local clients=("Dart.io" "Dart.web" "Dart.web(WSS)" "Go" "Kotlin" "Python" "TypeScript") + local anchor_label + + if [ -n "$anchor_language" ]; then + anchor_label="$(display_language_label "$anchor_language")" + case "$direction" in + server) + servers=("$anchor_label") + clients=("${server_capable[@]}") + ;; + client) + servers=("${server_capable[@]}") + clients=("$anchor_label") + ;; + both) + servers=("${server_capable[@]}") + clients=("${server_capable[@]}") + ;; + esac + fi printf '\n**언어 PASS 매트릭스**\n' printf '| 서버 \\ 클라이언트' @@ -556,19 +691,22 @@ print_cross_detail_table() { printf '|---|---:|---:|---:|---:|\n' for item in "${cross_cases[@]}"; do IFS='|' read -r server client dir cmd <<<"$item" + should_run_cross_case "$server" "$client" || continue key="$server|$client" printf '| %s -> %s | %s | %s | %s | %s |\n' \ "$(display_language_label "$server")" "$(display_language_label "$client")" \ "${cross_result[$key]:--}" "${cross_pass_lines[$key]:--}" "$expected_cross_pass_lines" "${cross_fail_lines[$key]:--}" done - for item in "${web_cases[@]}"; do - IFS='|' read -r server dir cmd <<<"$item" - key="$server" - printf '| %s -> Dart.web | %s | %s | %s | %s |\n' \ - "$server" "${web_ws_result[$key]:--}" "${web_ws_pass_lines[$key]:--}" "$expected_web_transport_pass_lines" "${web_fail_lines[$key]:--}" - printf '| %s -> Dart.web(WSS) | %s | %s | %s | %s |\n' \ - "$server" "${web_wss_result[$key]:--}" "${web_wss_pass_lines[$key]:--}" "$expected_web_transport_pass_lines" "${web_fail_lines[$key]:--}" - done + if [ -z "$anchor_language" ]; then + for item in "${web_cases[@]}"; do + IFS='|' read -r server dir cmd <<<"$item" + key="$server" + printf '| %s -> Dart.web | %s | %s | %s | %s |\n' \ + "$server" "${web_ws_result[$key]:--}" "${web_ws_pass_lines[$key]:--}" "$expected_web_transport_pass_lines" "${web_fail_lines[$key]:--}" + printf '| %s -> Dart.web(WSS) | %s | %s | %s | %s |\n' \ + "$server" "${web_wss_result[$key]:--}" "${web_wss_pass_lines[$key]:--}" "$expected_web_transport_pass_lines" "${web_fail_lines[$key]:--}" + done + fi } print_failures() { @@ -597,6 +735,7 @@ print_failures() { for item in "${cross_cases[@]}"; do IFS='|' read -r server client dir cmd <<<"$item" + should_run_cross_case "$server" "$client" || continue key="$server|$client" if [ "${cross_result[$key]:-}" = "FAIL" ]; then failed=1 @@ -608,23 +747,25 @@ print_failures() { fi done - for item in "${web_cases[@]}"; do - IFS='|' read -r server dir cmd <<<"$item" - key="$server" - if [ "${web_result[$key]:-}" = "BLOCKED" ]; then - failed=1 - printf '\n**차단: %s -> Dart.web 크로스테스트**\n' "$server" - printf '재현 명령: `%s`\n' "${web_cmds[$key]}" - printf '차단 사유: %s\n\n' "${web_block_reason[$key]:-unknown}" - elif [ "${web_result[$key]:-}" = "FAIL" ]; then - failed=1 - log_file="$log_dir/web_${server}.log" - printf '\n**실패: %s -> Dart.web 크로스테스트**\n' "$server" - printf '재현 명령: `%s`\n\n' "${web_cmds[$key]}" - tail -n 80 "$log_file" - printf '\n' - fi - done + if [ -z "$anchor_language" ]; then + for item in "${web_cases[@]}"; do + IFS='|' read -r server dir cmd <<<"$item" + key="$server" + if [ "${web_result[$key]:-}" = "BLOCKED" ]; then + failed=1 + printf '\n**차단: %s -> Dart.web 크로스테스트**\n' "$server" + printf '재현 명령: `%s`\n' "${web_cmds[$key]}" + printf '차단 사유: %s\n\n' "${web_block_reason[$key]:-unknown}" + elif [ "${web_result[$key]:-}" = "FAIL" ]; then + failed=1 + log_file="$log_dir/web_${server}.log" + printf '\n**실패: %s -> Dart.web 크로스테스트**\n' "$server" + printf '재현 명령: `%s`\n\n' "${web_cmds[$key]}" + tail -n 80 "$log_file" + printf '\n' + fi + done + fi return "$failed" } @@ -653,6 +794,7 @@ has_fail_results() { done for item in "${cross_cases[@]}"; do IFS='|' read -r server client dir cmd <<<"$item" + should_run_cross_case "$server" "$client" || continue key="$server|$client" if [ "${cross_result[$key]:-}" = "FAIL" ]; then return 0 @@ -685,6 +827,9 @@ print_report_body() { if [ "$mode" = "all" ] || [ "$mode" = "unit" ]; then print_unit_table fi + if [ "$mode" = "cross" ] && [ -n "$anchor_language" ]; then + print_unit_table + fi if [ "$mode" = "all" ] || [ "$mode" = "cross" ]; then print_language_pass_matrix print_cross_detail_table @@ -722,10 +867,16 @@ write_result_record() { printf '## 실행 정보\n\n' printf -- '- 실행 일시: %s\n' "$run_started_at" printf -- '- git ref: %s\n' "$git_ref" - printf -- '- 실행 명령: `bash agent-ops/skills/project/run-proto-socket-test-matrix/scripts/run_matrix.sh --%s`\n' "$mode" + if [ -n "$anchor_language" ]; then + printf -- '- 실행 명령: `bash agent-ops/skills/project/run-proto-socket-test-matrix/scripts/run_matrix.sh --%s --anchor %s --direction %s`\n' "$mode" "$anchor_slug" "$direction" + printf -- '- anchor: %s\n' "$anchor_slug" + printf -- '- direction: %s\n' "$direction" + else + printf -- '- 실행 명령: `bash agent-ops/skills/project/run-proto-socket-test-matrix/scripts/run_matrix.sh --%s`\n' "$mode" + fi printf -- '- exit code: %s\n' "$exit_code" printf -- '- 로그 디렉터리: `%s`\n' "$log_dir" - if [ "$mode" = "all" ] || [ "$mode" = "cross" ]; then + if [ -z "$anchor_language" ] && { [ "$mode" = "all" ] || [ "$mode" = "cross" ]; }; then printf -- '- Dart.web 실행 환경: %s\n' "$remote_web_execution" if [ "$remote_web_execution" = "remote" ]; then printf -- '- Dart.web remote host: `%s`\n' "$remote_web_host" @@ -758,8 +909,13 @@ main() { run_unit_tests ;; cross) - run_cross_tests - run_web_tests + if [ -n "$anchor_language" ]; then + run_unit_test_for_language "$anchor_language" + run_cross_tests + else + run_cross_tests + run_web_tests + fi ;; proto) run_proto_sync diff --git a/agent-ops/skills/project/run-proto-socket-test-matrix/scripts/run_test_by_change.sh b/agent-ops/skills/project/run-proto-socket-test-matrix/scripts/run_test_by_change.sh index 273bc8a..626773c 100755 --- a/agent-ops/skills/project/run-proto-socket-test-matrix/scripts/run_test_by_change.sh +++ b/agent-ops/skills/project/run-proto-socket-test-matrix/scripts/run_test_by_change.sh @@ -327,6 +327,29 @@ md_escape_cell() { printf '%s' "$1" | sed 's/|/\\|/g' } +is_anchor_kind() { + case "$1" in + functional-server-x5|functional-client-x5|functional-both-x5) return 0 ;; + esac + return 1 +} + +anchor_target_supported() { + case "$1" in + dart|go|kotlin|python|typescript) return 0 ;; + esac + return 1 +} + +anchor_direction_for_kind() { + case "$1" in + functional-server-x5) echo "server" ;; + functional-client-x5) echo "client" ;; + functional-both-x5) echo "both" ;; + *) return 1 ;; + esac +} + # ----------------------------------------------------------------------- # 라우팅 추천 기록을 위한 상태/중복 제어 헬퍼 # 추천 상태: @@ -729,12 +752,11 @@ main() { # ----------------------------------------------------------------------- # non-dry-run 실행 분기 # recommended 후보 중 지원 가능한 항목을 기존 wrapper command로 실행한다. - # anchor(functional-server-x5, functional-client-x5, functional-both-x5)는 - # anchor-runner-options 범위이므로 skipped로 기록한다. + # 언어 anchor x5 후보는 run_matrix.sh --cross --anchor/--direction으로 실행한다. # ----------------------------------------------------------------------- printf '\n### 실행 계획\n\n' - local supported_kinds="performance-quick stability-quick functional-full runner-docs-selfcheck docs-selfcheck" + local supported_kinds="performance-quick stability-quick functional-full functional-server-x5 functional-client-x5 functional-both-x5 runner-docs-selfcheck docs-selfcheck" local exec_log="" local skipped_log="" local nightly_log="" @@ -759,8 +781,12 @@ main() { for sup in $supported_kinds; do [ "$kd" = "$sup" ] && is_supported=1 && break done + if is_anchor_kind "$kd" && ! anchor_target_supported "$tg"; then + skipped_log="${skipped_log}- [anchor-skipped] ${kd} / ${tg}: anchor target이 지원 언어가 아님\n" + continue + fi if [ "$is_supported" -eq 0 ]; then - skipped_log="${skipped_log}- [anchor-skipped] ${kd} / ${tg}: anchor 실행은 anchor-runner-options 범위\n" + skipped_log="${skipped_log}- [skipped] ${kd} / ${tg}: 지원 실행 wrapper 없음\n" continue fi exec_log="${exec_log}- [실행 예정] ${kd} / ${tg}: ${rs}\n" @@ -791,8 +817,11 @@ main() { [ "$kd" = "$sup" ] && is_supported=1 && break done [ "$is_supported" -eq 0 ] && continue + if is_anchor_kind "$kd" && ! anchor_target_supported "${reco_targets[$i]}"; then + continue + fi - local cmd="" exit_code=0 record_path="" + local cmd="" exit_code=0 record_path="" anchor="" anchor_dir="" case "$kd" in performance-quick) cmd="bash $(printf '%q' "$script_dir/run_performance.sh") --quick" @@ -815,6 +844,15 @@ main() { exit_code=$? record_path="$(find "$repo_root/agent-test/runs" -maxdepth 1 -name '*proto-socket-full-matrix*' -type f 2>/dev/null | sort -r | head -n 1)" ;; + functional-server-x5|functional-client-x5|functional-both-x5) + anchor_dir="$(anchor_direction_for_kind "$kd")" + anchor="${reco_targets[$i]}" + cmd="bash $(printf '%q' "$script_dir/run_matrix.sh") --cross --anchor $anchor --direction $anchor_dir" + printf '\n--- 실행: %s ---\n' "$cmd" >&2 + (cd "$repo_root" && bash "$script_dir/run_matrix.sh" --cross --anchor "$anchor" --direction "$anchor_dir") >&2 + exit_code=$? + record_path="$(find "$repo_root/agent-test/runs" -maxdepth 1 -name "*proto-socket-anchor-${anchor}-${anchor_dir}-matrix*" -type f 2>/dev/null | sort -r | head -n 1)" + ;; runner-docs-selfcheck|docs-selfcheck) cmd="bash -n $(printf '%q' "$script_dir/run_test_by_change.sh")" printf '\n--- 실행: %s ---\n' "$cmd" >&2 diff --git a/agent-roadmap/ROADMAP.md b/agent-roadmap/ROADMAP.md index 68c8903..abc815a 100644 --- a/agent-roadmap/ROADMAP.md +++ b/agent-roadmap/ROADMAP.md @@ -32,8 +32,8 @@ Proto Socket은 여러 언어와 플랫폼에서 일관되게 동작하는 얇 - [고성능 병렬 운용 기준선과 최적화](archive/phase/stability-maintenance/milestones/high-performance-parallel-operations.md) - 상태: 완료; 목표: 현재 5개 언어 구현의 병렬 운용 성능을 언어별/transport별로 측정하고 gateway, queue, worker, serialization 병목을 최적화한다. - [언어별 성능 병목 개선](archive/phase/stability-maintenance/milestones/performance-hotspot-optimization.md) - 상태: 완료; 목표: 측정 결과에서 확인된 Dart TCP fixed latency/large payload 및 isolate receive path hardening, TypeScript WS large payload, Kotlin WS latency/slow-mix 검증 모델, TypeScript gateway `worker_threads` overhead 병목을 안정성 hard gate와 단일 mandatory receive path 원칙을 유지하면서 개선하고, Go/Python reference 기준점을 보강한다. - [워크스페이스 포트/환경 표준화](archive/phase/stability-maintenance/milestones/workspace-port-env-standardization.md) - 상태: 완료; 목표: proto-socket이 runtime service port를 소유하지 않는다는 점과 cross-language test runner의 fixed local port 대역을 workspace 표준 예외로 문서화한다. -- [변경 기반 테스트 라우팅 정형화](milestones/change-aware-test-routing.md) - 상태: [진행중]; 목표: 마지막 통과 테스트 지점과 현재 변경 내용을 분석해 기능, 속도, 안정성 테스트 중 필요한 검증 범위를 자동 선택하고, 언어별 anchor x5와 야간 장시간 측정을 분리한다. -- [야간 대용량 패킷 성능 기준선](milestones/nightly-large-payload-baseline.md) - 상태: [계획]; 목표: 64KB/1MB payload 성능 baseline과 회귀 판단을 실행 host local time 20:00 이후 야간 window에서 별도 수집해 주간 작업 부하 편차와 분리한다. +- [변경 기반 테스트 라우팅 정형화](archive/phase/stability-maintenance/milestones/change-aware-test-routing.md) - 상태: 완료; 목표: 마지막 통과 테스트 지점과 현재 변경 내용을 분석해 기능, 속도, 안정성 테스트 중 필요한 검증 범위를 자동 선택하고, 언어별 anchor x5와 야간 장시간 측정을 분리한다. +- [야간 대용량 패킷 성능 기준선](milestones/nightly-large-payload-baseline.md) - 상태: [진행중]; 목표: 64KB/1MB payload 성능 baseline과 회귀 판단을 실행 host local time 20:00 이후 야간 window에서 별도 수집해 주간 작업 부하 편차와 분리한다. - [대용량 WS/병렬 전송 후속 최적화](milestones/large-payload-followup-optimization.md) - 상태: [계획]; 목표: 야간 기준선에서 병목이 유지되는 row를 근거로 TypeScript WS 1MB, WS fixed latency, Kotlin WS 1MB, Dart large-packet guard 후보를 후속 최적화로 구체화한다. ### 남은 native platform 포팅 diff --git a/agent-roadmap/milestones/change-aware-test-routing.md b/agent-roadmap/archive/phase/stability-maintenance/milestones/change-aware-test-routing.md similarity index 84% rename from agent-roadmap/milestones/change-aware-test-routing.md rename to agent-roadmap/archive/phase/stability-maintenance/milestones/change-aware-test-routing.md index 20666a3..4f8a61c 100644 --- a/agent-roadmap/milestones/change-aware-test-routing.md +++ b/agent-roadmap/archive/phase/stability-maintenance/milestones/change-aware-test-routing.md @@ -10,7 +10,7 @@ ## 상태 -[진행중] +[완료] ## 구현 잠금 @@ -72,24 +72,27 @@ 스킬이 선택한 라우팅을 실제 명령으로 연결한다. -- [ ] [routing-skill] 프로젝트 스킬 또는 기존 `run-proto-socket-test-matrix` 스킬에 "작업된 내용을 바탕으로 테스트" 요청 라우팅 절차를 추가한다. 검증: 사용자가 언어와 테스트 종류를 지정하지 않아도 변경 분석 결과와 선택한 검증 범위를 먼저 보고한다. -- [ ] [auto-test-shell] `run_test_by_change.sh` 자동 라우팅 shell을 추가해 `테스트 해봐` 요청의 기본 실행 단위로 쓴다. 검증: 마지막 PASS 지점, 변경 분류, 선택된 하위 command가 결과 기록에 남는다. -- [ ] [speed-test-shell] `run_speed_test.sh` 속도 전용 shell을 추가해 quick/daytime과 full/nightly 후보를 관리한다. 검증: 성능 관련 변경에서 기존 `run_performance.sh`/`run_stress.sh`를 직접 외우지 않아도 실행된다. -- [ ] [stability-test-shell] `run_stability_test.sh` 안정성 전용 shell을 추가해 quick stress와 nightly long-run 후보를 관리한다. 검증: stability hard gate 요약이 별도 결과로 남는다. +- [x] [routing-skill] 프로젝트 스킬 또는 기존 `run-proto-socket-test-matrix` 스킬에 "작업된 내용을 바탕으로 테스트" 요청 라우팅 절차를 추가한다. 검증: 사용자가 언어와 테스트 종류를 지정하지 않아도 변경 분석 결과와 선택한 검증 범위를 먼저 보고한다. +- [x] [auto-test-shell] `run_test_by_change.sh` 자동 라우팅 shell을 추가해 `테스트 해봐` 요청의 기본 실행 단위로 쓴다. 검증: 마지막 PASS 지점, 변경 분류, 선택된 하위 command가 결과 기록에 남는다. +- [x] [speed-test-shell] `run_speed_test.sh` 속도 전용 shell을 추가해 quick/daytime과 full/nightly 후보를 관리한다. 검증: 성능 관련 변경에서 기존 `run_performance.sh`/`run_stress.sh`를 직접 외우지 않아도 실행된다. +- [x] [stability-test-shell] `run_stability_test.sh` 안정성 전용 shell을 추가해 quick stress와 nightly long-run 후보를 관리한다. 검증: stability hard gate 요약이 별도 결과로 남는다. - [x] [full-test-shell] `run_full_test.sh` 전체 테스트 shell을 추가해 functional full과 nightly heavy 후보를 분리한다. 검증: 기존 `run_matrix.sh --all`과 performance/stability full이 한 결과 계약 안에서 구분된다. -- [ ] [anchor-runner-options] 필요한 경우 각 shell 또는 기존 runner에 `--anchor `와 `--direction server|client|both` 또는 동등한 개별 명령 조합을 추가한다. 검증: 수정 언어 중심 x5를 full 5x5 없이 실행할 수 있다. -- [ ] [test-profile-docs] `agent-test/local/rules.md`와 관련 profile 문서에 4개 shell entrypoint와 주야간 분리 기준을 반영한다. 검증: 테스트 문서만 읽어도 네 라우팅의 명령과 판정 기준을 알 수 있다. -- [ ] [result-report-contract] 결과 보고에 선택 이유, 실행 명령, 결과 record, skipped/nightly-pending 항목을 남긴다. 검증: 실행하지 않은 야간 full을 PASS로 오인하지 않는다. +- [x] [anchor-runner-options] 필요한 경우 각 shell 또는 기존 runner에 `--anchor `와 `--direction server|client|both` 또는 동등한 개별 명령 조합을 추가한다. 검증: 수정 언어 중심 x5를 full 5x5 없이 실행할 수 있다. +- [x] [test-profile-docs] `agent-test/local/rules.md`와 관련 profile 문서에 4개 shell entrypoint와 주야간 분리 기준을 반영한다. 검증: 테스트 문서만 읽어도 네 라우팅의 명령과 판정 기준을 알 수 있다. +- [x] [result-report-contract] 결과 보고에 선택 이유, 실행 명령, 결과 record, skipped/nightly-pending 항목을 남긴다. 검증: 실행하지 않은 야간 full을 PASS로 오인하지 않는다. ## 완료 리뷰 -- 상태: 없음 -- 요청일: 없음 -- 완료 근거: 없음 +- 상태: 승인됨 +- 요청일: 2026-06-10 +- 완료 근거: + - `run_matrix.sh --cross --anchor --direction server|client|both`가 추가되어 언어 anchor x5를 full 5x5 없이 실행할 수 있다. + - `run_test_by_change.sh`가 언어별 `functional-server-x5`, `functional-client-x5`, `functional-both-x5` 추천을 anchor matrix 실행으로 연결한다. + - focused 검증 `bash agent-ops/skills/project/run-proto-socket-test-matrix/scripts/run_matrix.sh --cross --anchor go --direction server` PASS, 결과 기록 `agent-test/runs/20260610-104319-proto-socket-anchor-go-server-matrix.md`. - 리뷰 필요: - - [ ] 사용자가 완료 결과를 확인했다 - - [ ] archive 이동을 승인했다 -- 리뷰 코멘트: 없음 + - [x] 사용자가 완료 결과를 확인했다 + - [x] archive 이동을 승인했다 +- 리뷰 코멘트: 2026-06-10 사용자 요청으로 완료 승인 후 archive 이동. ## 범위 제외 @@ -117,3 +120,5 @@ - 완료: `agent-task/archive/2026/06/m-change-aware-test-routing/04_user_entrypoints_full_route/complete.log` -> `full-test-route` - 완료(직접 처리): `user-entrypoints` auto/speed/stability dry-run 정책 보강 -> `auto-test-route`, `speed-test-route`, `stability-test-route`; 검증=`bash -n .../run_test_by_change.sh`, focused temp repo route smoke(auto/speed/stability), `rg --sort path ...` - 계획 작성: `agent-task/m-change-aware-test-routing/05_user_entrypoint_runner_contract/PLAN-cloud-G07.md` -> `routing-skill`, `auto-test-shell`, `speed-test-shell`, `stability-test-shell`, `test-profile-docs`, `result-report-contract` + - 완료(직접 처리): `skill-and-runner-contract` user-entrypoint runner 계약 동기화 -> `routing-skill`, `auto-test-shell`, `speed-test-shell`, `stability-test-shell`, `test-profile-docs`, `result-report-contract`; 검증=`bash -n .../run_test_by_change.sh .../run_speed_test.sh .../run_stability_test.sh .../run_full_test.sh`, `run_test_by_change.sh --route auto --dry-run`, `run_speed_test.sh --dry-run`, `run_stability_test.sh --dry-run`, `run_full_test.sh --dry-run` + - 완료(직접 처리): `skill-and-runner-contract` anchor x5 실행 연결 -> `anchor-runner-options`; 검증=`bash -n .../run_matrix.sh .../run_test_by_change.sh .../run_speed_test.sh .../run_stability_test.sh .../run_full_test.sh`, invalid anchor/mode guard, direction-without-anchor guard, `run_matrix.sh --cross --anchor go --direction server` PASS (`agent-test/runs/20260610-104319-proto-socket-anchor-go-server-matrix.md`) diff --git a/agent-roadmap/milestones/nightly-large-payload-baseline.md b/agent-roadmap/milestones/nightly-large-payload-baseline.md index 7cdfb09..80df237 100644 --- a/agent-roadmap/milestones/nightly-large-payload-baseline.md +++ b/agent-roadmap/milestones/nightly-large-payload-baseline.md @@ -10,7 +10,7 @@ ## 상태 -[계획] +[진행중] ## 구현 잠금 @@ -33,25 +33,25 @@ 대용량 payload baseline은 낮 시간 작업 부하와 분리한다. -- [ ] [time-window-rule] 64KB/1MB payload baseline 후보는 실행 host local time 기준 20:00 이후 시작한 record만 인정한다. 검증: 결과 기록의 실행 일시와 host timezone 또는 실행 메모가 야간 조건을 확인 가능하게 남는다. -- [ ] [daytime-policy] 20:00 이전에 수집한 대용량 payload 결과는 exploratory record로 표시하고, baseline/regression 완료 근거에서 제외한다. 검증: milestone 완료 근거에 주간 record가 baseline으로 쓰이지 않는다. +- [x] [time-window-rule] 64KB/1MB payload baseline 후보는 실행 host local time 기준 20:00 이후 시작한 record만 인정한다. 검증: 2026-06-10 실행 메모에 host local time `2026-06-10 21:18:24 KST +0900` full wrapper 시작과 `2026-06-10 21:40:06 KST` payload focused record 생성 근거를 남겼다. +- [x] [daytime-policy] 20:00 이전에 수집한 대용량 payload 결과는 exploratory record로 표시하고, baseline/regression 완료 근거에서 제외한다. 검증: 2026-06-10 완료 근거는 야간 focused record만 baseline 후보로 사용하고, 기존 주간/시간대 미확인 record는 방향성 비교용으로만 남겼다. ### Epic: [payload-baseline] 대용량 payload 기준선 작업 부하가 낮은 시간대에 같은 profile을 반복해 편차를 줄인다. -- [ ] [night-full-record] 20:00 이후 `bash agent-ops/skills/project/run-proto-socket-test-matrix/scripts/run_performance.sh --full`을 실행해 야간 full performance record를 남긴다. 검증: same-language, cross-language, TypeScript gateway 구성요소가 모두 기록되고 대용량 payload rows가 포함된다. -- [ ] [payload-focused-record] 20:00 이후 `run_stress.sh --full --profile payload` 계열 focused record를 수집해 64KB/1MB TCP/WS rows를 별도로 확인한다. 검증: Dart, Go, Kotlin, Python, TypeScript payload rows가 stability hard gate 0으로 기록된다. -- [ ] [repeatability] 필요하면 서로 다른 야간 window에서 최소 2회 이상 반복해 p99/throughput 편차를 비교한다. 검증: 같은 host/runtime/profile의 night records끼리 비교하고, 편차가 큰 row는 baseline 확정 대신 watchlist로 남긴다. +- [ ] [night-full-record] 20:00 이후 `bash agent-ops/skills/project/run-proto-socket-test-matrix/scripts/run_performance.sh --full`을 실행해 야간 full performance record를 남긴다. 검증: same-language, cross-language, TypeScript gateway 구성요소가 모두 기록되고 대용량 payload rows가 포함된다. 진행 메모: 2026-06-10 21:18 KST에 시작했으나 Dart same-language full stress 단계가 20분 이상 record 없이 지속되어 중단했다. 2일차 장기 실행으로 이월한다. +- [x] [payload-focused-record] 20:00 이후 `run_stress.sh --full --profile payload` 계열 focused record를 수집해 64KB/1MB TCP/WS rows를 별도로 확인한다. 검증: `agent-test/runs/20260610-124006-proto-socket-stress-full.md`에서 Dart, Go, Kotlin, Python, TypeScript payload rows가 모두 PASS이고 stability violations 0으로 기록됐다. +- [x] [repeatability] 필요하면 2회 이상 반복해 p99/throughput 편차를 비교한다. 검증: `agent-test/runs/20260610-124006-proto-socket-stress-full.md`와 `agent-test/runs/20260610-131132-proto-socket-stress-full.md`를 같은 host/runtime/profile의 night records로 비교했다. 모든 64KB/1MB row는 PASS/PASS와 stability violations 0을 유지했고, 편차가 큰 row는 baseline 확정값 대신 watchlist로 남겼다. ### Epic: [large-packet-watchlist] 큰 패킷 병목 감시 기존 최적화가 실제 idle 조건에서도 유지되는지 확인한다. -- [ ] [dart-large-packet] Dart TCP/WS 64KB/1MB rows가 야간 기준에서도 안정성 hard gate를 유지하고, 주간 대비 방향성이 개선으로 유지되는지 확인한다. -- [ ] [kotlin-ws-large-packet] Kotlin WS 64KB/1MB rows의 p99, throughput, memory, queue backlog를 야간 기준으로 다시 확인한다. -- [ ] [typescript-ws-large-packet] TypeScript WS 1MB row를 야간 기준으로 재측정하고, 병목이 여전히 남으면 다음 최적화 후보로 분리한다. -- [ ] [reference-large-packet] Go/Python TCP/WS 1MB rows를 야간 reference fast/medium path로 확정한다. +- [x] [dart-large-packet] Dart TCP/WS 64KB/1MB rows가 야간 기준에서도 안정성 hard gate를 유지하고, 주간 대비 방향성이 개선으로 유지되는지 확인한다. 검증: 2026-06-10 focused records에서 Dart 64KB/1MB TCP/WS 모두 PASS, stability violations 0. WS 1MB는 2회 모두 2026-06-07 full record 대비 개선됐고, TCP 1MB는 1회차 개선 후 2회차 p99가 141.681ms로 흔들려 watchlist에 남긴다. +- [x] [kotlin-ws-large-packet] Kotlin WS 64KB/1MB rows의 p99, throughput, memory, queue backlog를 야간 기준으로 다시 확인한다. 검증: Kotlin WS 64KB p99 13.461ms/13.049ms, throughput 1068.8/970.4rps, queue backlog 1/2; WS 1MB p99 75.940ms/100.032ms, throughput 113.6/92.6rps, queue backlog 1/1; stability violations 0. WS 1MB p99 편차는 watchlist로 남긴다. +- [x] [typescript-ws-large-packet] TypeScript WS 1MB row를 야간 기준으로 재측정하고, 병목이 여전히 남으면 다음 최적화 후보로 분리한다. 검증: TypeScript WS 1MB p99 226.008ms/237.395ms, throughput 33.5/33.3rps, stability violations 0. Go/Python reference 대비 낮은 throughput과 높은 p99가 반복되어 후속 최적화 후보로 남긴다. +- [x] [reference-large-packet] Go/Python TCP/WS 1MB rows를 야간 reference fast/medium path로 확정한다. 검증: Go 1MB TCP/WS p99 23.201ms/28.900ms, Python 1MB TCP/WS p99 16.776ms/44.841ms, 모두 stability violations 0으로 기록됐다. ## 완료 리뷰 @@ -76,3 +76,23 @@ - 선행 작업: `언어별 성능 병목 개선`, `성능 기록 판정 자동화` - 후속 작업: `대용량 WS/병렬 전송 후속 최적화` 스케치에서 야간 기준에서도 병목이 유지되는 row를 구현 후보로 승격한다. - 표준선: 대용량 payload baseline은 실행 host local time 기준 20:00 이후 시작한 결과만 인정한다. + +## 2026-06-10 진행 메모 + +- host local time 확인: `2026-06-10 21:18:24 KST +0900`. +- full wrapper 시도: `bash agent-ops/skills/project/run-proto-socket-test-matrix/scripts/run_performance.sh --full`. +- full wrapper 결과: `/tmp/proto-socket-performance.yAs0NV/same-language.log`에 Dart same-language full stress 시작만 남고 20분 이상 record가 생성되지 않아 중단했다. 중단 시 실행 중이던 프로세스 그룹은 종료 확인했다. +- payload focused 실행: `bash agent-ops/skills/project/run-proto-socket-test-matrix/scripts/run_stress.sh --full --profile payload`. +- payload focused 결과: `agent-test/runs/20260610-124006-proto-socket-stress-full.md`, overall PASS, 언어별 PASS 5/5, required skip 0, stability violations 0. +- 주요 watchlist: Dart TCP/WS 1MB PASS, Kotlin WS 64KB/1MB PASS, TypeScript WS 1MB PASS이나 p99 226.008ms와 33.5rps로 후속 최적화 후보 유지, Go/Python 1MB reference rows PASS. +- 2회차 host local time 확인: `2026-06-10 22:11:12 KST +0900`. +- 2회차 payload focused 결과: `agent-test/runs/20260610-131132-proto-socket-stress-full.md`, overall PASS, 언어별 PASS 5/5, required skip 0, stability violations 0. +- 1회차 대비 2회차 반복성: 모든 64KB/1MB row가 PASS/PASS를 유지했다. TypeScript WS 1MB는 p99 226.008ms -> 237.395ms, throughput 33.5rps -> 33.3rps로 병목이 안정적으로 재현됐다. Dart TCP 1MB, Kotlin TCP/WS 1MB, Go WS 64KB는 p99 편차가 커서 baseline 확정값 대신 watchlist로 둔다. + +## 2일차 핸드오프 + +- 실행 전 host local time이 20:00 이후인지 `date '+%Y-%m-%d %H:%M:%S %Z %z'`로 먼저 남긴다. +- 1순위는 full performance record 재수집이다: `bash agent-ops/skills/project/run-proto-socket-test-matrix/scripts/run_performance.sh --full`. +- full wrapper가 다시 오래 걸리면 Dart same-language full stress에서 멈추는지 먼저 확인하고, full wrapper 완료 전에 baseline 완료 판정을 하지 않는다. +- 2순위는 필요 시 다른 야간 window repeatability 강화다: `bash agent-ops/skills/project/run-proto-socket-test-matrix/scripts/run_stress.sh --full --profile payload`를 한 번 더 실행해 2026-06-10 2회 기록과 p99/throughput 편차를 비교한다. +- 20:00 이전 결과나 host timezone 확인이 없는 결과는 baseline/regression 완료 근거가 아니라 exploratory 또는 방향성 참고로만 사용한다.