update agent-ops rules and test matrix skill

This commit is contained in:
toki 2026-05-30 23:30:43 +09:00
parent 617ec02090
commit f89e42fdb7
3 changed files with 136 additions and 39 deletions

View file

@ -53,6 +53,10 @@ VERSIONING.md — 프로토콜/패키지 버전 정책
- 이 프로젝트의 주 사용 방식과 릴리즈 기준은 package registry나 CI/CD 배포 흐름이 아니라 Git ref/tag 기반 소비다.
- 검증 루프는 내부 로컬 매트릭스 실행 결과를 기준으로 판단한다.
- 기본 검증 명령은 `bash agent-ops/skills/project/run-proto-socket-test-matrix/scripts/run_matrix.sh --all`이다.
- 언어 PASS 매트릭스는 서버 가능한 구현만 행으로 둔다: `Dart.io`, `Go`, `Kotlin`, `Python`, `TypeScript`.
- 언어 PASS 매트릭스의 클라이언트 열은 `Dart.io`, `Dart.web`, `Dart.web(WSS)`, `Go`, `Kotlin`, `Python`, `TypeScript` 순서로 둔다.
- `Dart.web``Dart.web(WSS)`는 browser client runtime이므로 서버 행에 넣지 않는다.
- Dart.web 상세는 `Server -> Dart.web``Server -> Dart.web(WSS)`를 분리하고, 각각 `PASS scenarios` expected `2`로 기록한다.
- 테스트 coverage 평가는 라인/브랜치 수치가 아니라 프로토콜 계약 시나리오가 매트릭스에서 빠짐없이 검증되는지로 판단한다.
- Dart.web remote browser host 사용은 의도된 local 테스트 환경이다. 환경을 이전할 때는 그대로 유지할 규칙이 아니라 새 local 환경 규칙으로 재정의해야 한다.
- Dart.web WSS는 테스트용 self-signed certificate의 SPKI를 허용하는 Chrome 실행 wrapper로 local/remote 브라우저 매트릭스에 포함한다.

View file

@ -104,7 +104,7 @@ tools/check_proto_sync.sh
- Proto 동기화 검사는 `tools/check_proto_sync.sh` 종료 코드가 0이면 `PASS`.
- 크로스테스트는 각 방향의 `PASS scenario=...` 라인 수가 기대 개수와 일치하는지도 검증한다. 기본 cross matrix는 16개, Dart.web 표는 2개(send-push, request-response)를 기대한다.
- 동일 언어 대각선 셀은 `unit` 또는 `all` 범위에서 해당 언어 동일 언어 테스트가 통과했을 때 `PASS`로 표시한다. `cross`만 실행했다면 대각선은 `-`로 둔다.
- Dart.web 클라이언트는 브라우저 WS만 지원하므로 기존 cross matrix(Dart 열)에는 포함하지 않고 별도 Dart.web 표로 보고한다. TCP/TLS/WSS는 `N/A` 또는 `Deferred`로 표기한다.
- Dart.web 클라이언트는 브라우저 WS/WSS만 지원하므로 서버 행에는 넣지 않고, `Dart.web``Dart.web(WSS)` 클라이언트 열로 보고한다.
5. **결과 보고**
- 요청 범위에 맞춰 proto 동기화 표, 동일 언어 테스트 표, 서버/클라이언트 크로스 통신 표를 한국어로 보고한다.
@ -133,22 +133,27 @@ tools/check_proto_sync.sh
| Dart | `dart pub get && dart test && dart compile js test/browser_ws_import_compile.dart -o /tmp/proto_socket_browser_ws_import_compile.js` | PASS |
**언어 PASS 매트릭스**
| 서버 \ 클라이언트 | Dart.io | Dart.web | Go | Kotlin | Python | TypeScript |
|---|---|---|---|---|---|---|
| Dart.io | PASS | PASS | PASS | PASS | PASS | PASS |
| Go | PASS | PASS | PASS | PASS | PASS | PASS |
| Kotlin | PASS | PASS | PASS | PASS | PASS | PASS |
| Python | PASS | PASS | PASS | PASS | PASS | PASS |
| TypeScript | PASS | PASS | PASS | PASS | PASS | PASS |
| 서버 \ 클라이언트 | Dart.io | Dart.web | Dart.web(WSS) | Go | Kotlin | Python | TypeScript |
|---|---|---|---|---|---|---|---|
| Dart.io | PASS | PASS | PASS | PASS | PASS | PASS | PASS |
| Go | PASS | PASS | PASS | PASS | PASS | PASS | PASS |
| Kotlin | PASS | PASS | PASS | PASS | PASS | PASS | PASS |
| Python | PASS | PASS | PASS | PASS | PASS | PASS | PASS |
| TypeScript | PASS | PASS | PASS | PASS | PASS | PASS | PASS |
**크로스테스트 상세**
| 방향 | 결과 | PASS scenarios | Expected | FAIL lines |
|---|---:|---:|---:|---:|
| Dart.io -> Dart.web | PASS | 4 | 4 | 0 |
| Go -> Dart.web | PASS | 4 | 4 | 0 |
| Kotlin -> Dart.web | PASS | 4 | 4 | 0 |
| Python -> Dart.web | PASS | 4 | 4 | 0 |
| TypeScript -> Dart.web | PASS | 4 | 4 | 0 |
| Dart.io -> Dart.web | PASS | 2 | 2 | 0 |
| Dart.io -> Dart.web(WSS) | PASS | 2 | 2 | 0 |
| Go -> Dart.web | PASS | 2 | 2 | 0 |
| Go -> Dart.web(WSS) | PASS | 2 | 2 | 0 |
| Kotlin -> Dart.web | PASS | 2 | 2 | 0 |
| Kotlin -> Dart.web(WSS) | PASS | 2 | 2 | 0 |
| Python -> Dart.web | PASS | 2 | 2 | 0 |
| Python -> Dart.web(WSS) | PASS | 2 | 2 | 0 |
| TypeScript -> Dart.web | PASS | 2 | 2 | 0 |
| TypeScript -> Dart.web(WSS) | PASS | 2 | 2 | 0 |
```
## 금지 사항

View file

@ -106,13 +106,18 @@ web_cases=(
"TypeScript|$repo_root/typescript|./node_modules/.bin/tsx crosstest/typescript_dart_web.ts"
)
declare -A web_result
declare -A web_ws_result
declare -A web_wss_result
declare -A web_status
declare -A web_pass_lines
declare -A web_ws_pass_lines
declare -A web_wss_pass_lines
declare -A web_fail_lines
declare -A web_cmds
declare -A web_block_reason
expected_web_pass_lines=4
expected_web_transport_pass_lines=2
count_lines() {
local pattern="$1"
@ -222,6 +227,9 @@ if [ ! -d \"\$repo_dir/.git\" ]; then
git clone \"\$repo_url\" \"\$repo_dir\"
fi
cd \"\$repo_dir\"
if ! git diff --quiet || ! git diff --cached --quiet || [ -n \"\$(git ls-files --others --exclude-standard)\" ]; then
git stash push -u -m \"proto-socket matrix remote test stash \$(date -u +%Y%m%d-%H%M%S)\" >/dev/null
fi
git fetch origin --prune
git checkout \"\$repo_ref\"
git pull --ff-only origin \"\$repo_ref\"
@ -239,6 +247,34 @@ printf 'remote Dart.web git ref: %s\n' \"\$(git rev-parse --short HEAD)\"
"
}
sync_remote_web_worktree() {
local changed_list sync_count
changed_list="$log_dir/remote_web_changed_files.zlist"
{
git -C "$repo_root" diff --name-only -z
git -C "$repo_root" diff --cached --name-only -z
git -C "$repo_root" ls-files --others --exclude-standard -z
} | sort -zu >"$changed_list"
if [ ! -s "$changed_list" ]; then
return 0
fi
sync_count="$(tr '\0' '\n' <"$changed_list" | sed '/^$/d' | wc -l | tr -d ' ')"
(
cd "$repo_root" &&
tar --null -T "$changed_list" -cf -
) | remote_exec "
set -e
repo_parent=$remote_web_root_expr
repo_name=$(single_quote "$remote_web_repo_name")
repo_dir=\"\$repo_parent/\$repo_name\"
cd \"\$repo_dir\"
tar -xf -
"
remote_web_prepare_summary="${remote_web_prepare_summary} local worktree sync: ${sync_count} files "
}
run_remote_web_logged() {
local server="$1"
local dir="$2"
@ -316,8 +352,40 @@ run_cross_tests() {
done
}
set_web_result() {
local key="$1"
local status="$2"
local log_file="$3"
local pass_count fail_count ws_pass_count wss_pass_count
pass_count="$(count_lines '^PASS scenario=' "$log_file")"
ws_pass_count="$(count_lines '^PASS scenario=ws-' "$log_file")"
wss_pass_count="$(count_lines '^PASS scenario=wss-' "$log_file")"
fail_count="$(count_lines '^FAIL ' "$log_file")"
web_status[$key]="$status"
web_pass_lines[$key]="$pass_count"
web_ws_pass_lines[$key]="$ws_pass_count"
web_wss_pass_lines[$key]="$wss_pass_count"
web_fail_lines[$key]="$fail_count"
if [ "$status" -eq 0 ] && [ "$fail_count" -eq 0 ] && [ "$pass_count" -eq "$expected_web_pass_lines" ]; then
web_result[$key]="PASS"
else
web_result[$key]="FAIL"
fi
if [ "$status" -eq 0 ] && [ "$fail_count" -eq 0 ] && [ "$ws_pass_count" -eq "$expected_web_transport_pass_lines" ]; then
web_ws_result[$key]="PASS"
else
web_ws_result[$key]="FAIL"
fi
if [ "$status" -eq 0 ] && [ "$fail_count" -eq 0 ] && [ "$wss_pass_count" -eq "$expected_web_transport_pass_lines" ]; then
web_wss_result[$key]="PASS"
else
web_wss_result[$key]="FAIL"
fi
}
run_web_tests() {
local item server dir cmd key log_file status pass_count fail_count remote_reason
local item server dir cmd key log_file status remote_reason
if ! chrome_available; then
if ! prepare_remote_web_repo >"$log_dir/remote_web_prepare.log" 2>&1; then
remote_reason="$(tail -n 20 "$log_dir/remote_web_prepare.log" | tr '\n' ' ')"
@ -327,8 +395,12 @@ run_web_tests() {
web_cmds[$key]="ssh $remote_web_host '(cd $remote_web_root_expr/$remote_web_repo_name/${dir#$repo_root/} && $cmd)'"
web_status[$key]="127"
web_pass_lines[$key]="0"
web_ws_pass_lines[$key]="0"
web_wss_pass_lines[$key]="0"
web_fail_lines[$key]="0"
web_result[$key]="BLOCKED"
web_ws_result[$key]="BLOCKED"
web_wss_result[$key]="BLOCKED"
web_block_reason[$key]="Remote Dart.web environment unavailable: $remote_reason"
printf 'BLOCKED remote web %s->Dart.web: %s\n' "$server" "$remote_reason" >&2
done
@ -336,6 +408,25 @@ run_web_tests() {
fi
remote_web_execution="remote"
remote_web_prepare_summary="$(grep '^remote Dart.web ' "$log_dir/remote_web_prepare.log" 2>/dev/null | tr '\n' ' ')"
if ! sync_remote_web_worktree >"$log_dir/remote_web_sync.log" 2>&1; then
remote_reason="$(tail -n 20 "$log_dir/remote_web_sync.log" | tr '\n' ' ')"
for item in "${web_cases[@]}"; do
IFS='|' read -r server dir cmd <<<"$item"
key="$server"
web_cmds[$key]="ssh $remote_web_host '(cd $remote_web_root_expr/$remote_web_repo_name/${dir#$repo_root/} && $cmd)'"
web_status[$key]="127"
web_pass_lines[$key]="0"
web_ws_pass_lines[$key]="0"
web_wss_pass_lines[$key]="0"
web_fail_lines[$key]="0"
web_result[$key]="BLOCKED"
web_ws_result[$key]="BLOCKED"
web_wss_result[$key]="BLOCKED"
web_block_reason[$key]="Remote Dart.web worktree sync failed: $remote_reason"
printf 'BLOCKED remote web %s->Dart.web: %s\n' "$server" "$remote_reason" >&2
done
return
fi
for item in "${web_cases[@]}"; do
IFS='|' read -r server dir cmd <<<"$item"
@ -344,16 +435,7 @@ run_web_tests() {
web_cmds[$key]="ssh $remote_web_host '(cd $remote_web_root_expr/$remote_web_repo_name/${dir#$repo_root/} && $cmd)'"
run_remote_web_logged "$server" "$dir" "$cmd" "$log_file"
status=$?
pass_count="$(count_lines '^PASS scenario=' "$log_file")"
fail_count="$(count_lines '^FAIL ' "$log_file")"
web_status[$key]="$status"
web_pass_lines[$key]="$pass_count"
web_fail_lines[$key]="$fail_count"
if [ "$status" -eq 0 ] && [ "$fail_count" -eq 0 ] && [ "$pass_count" -eq "$expected_web_pass_lines" ]; then
web_result[$key]="PASS"
else
web_result[$key]="FAIL"
fi
set_web_result "$key" "$status" "$log_file"
done
return
fi
@ -365,16 +447,7 @@ run_web_tests() {
web_cmds[$key]="(cd ${dir#$repo_root/} && $cmd)"
run_logged "web $server->Dart.web: $cmd" "$dir" "$cmd" "$log_file"
status=$?
pass_count="$(count_lines '^PASS scenario=' "$log_file")"
fail_count="$(count_lines '^FAIL ' "$log_file")"
web_status[$key]="$status"
web_pass_lines[$key]="$pass_count"
web_fail_lines[$key]="$fail_count"
if [ "$status" -eq 0 ] && [ "$fail_count" -eq 0 ] && [ "$pass_count" -eq "$expected_web_pass_lines" ]; then
web_result[$key]="PASS"
else
web_result[$key]="FAIL"
fi
set_web_result "$key" "$status" "$log_file"
done
}
@ -419,7 +492,12 @@ language_matrix_cell() {
local server client key
if [ "$client_label" = "Dart.web" ]; then
echo "${web_result[$server_label]:--}"
echo "${web_ws_result[$server_label]:--}"
return
fi
if [ "$client_label" = "Dart.web(WSS)" ]; then
echo "${web_wss_result[$server_label]:--}"
return
fi
@ -442,11 +520,19 @@ language_matrix_cell() {
print_language_pass_matrix() {
local server client
local servers=("Dart.io" "Go" "Kotlin" "Python" "TypeScript")
local clients=("Dart.io" "Dart.web" "Go" "Kotlin" "Python" "TypeScript")
local clients=("Dart.io" "Dart.web" "Dart.web(WSS)" "Go" "Kotlin" "Python" "TypeScript")
printf '\n**언어 PASS 매트릭스**\n'
printf '| 서버 \\ 클라이언트 | Dart.io | Dart.web | Go | Kotlin | Python | TypeScript |\n'
printf '|---|---|---|---|---|---|---|\n'
printf '| 서버 \\ 클라이언트'
for client in "${clients[@]}"; do
printf ' | %s' "$client"
done
printf ' |\n'
printf '|---'
for client in "${clients[@]}"; do
printf '|---'
done
printf '|\n'
for server in "${servers[@]}"; do
printf '| %s' "$server"
for client in "${clients[@]}"; do
@ -472,7 +558,9 @@ print_cross_detail_table() {
IFS='|' read -r server dir cmd <<<"$item"
key="$server"
printf '| %s -> Dart.web | %s | %s | %s | %s |\n' \
"$server" "${web_result[$key]:--}" "${web_pass_lines[$key]:--}" "$expected_web_pass_lines" "${web_fail_lines[$key]:--}"
"$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
}