Skip to content

[DONE] 정리 4단계 PR 20 — 오디오 WebSocket 벡터가 가상 패널에서 돌고, check:audio-vectors 가 PR 마다 본다 - #85

Merged
patternflow-bot merged 3 commits into
devfrom
claude/cleanup-step4-pr20-nwprtu
Oct 15, 2026
Merged

patternflow-bot merged 3 commits into
devfrom
claude/cleanup-step4-pr20-nwprtu

Conversation

@patternflow-bot

@patternflow-bot patternflow-bot commented Oct 15, 2026 •

Copy link
Copy Markdown

dev / https://claude.ai/code/session_01M9se1jvH1i5Sc12oaN2xSW

정리 4단계 계획서 표의 PR 20 이다. audio-ws-spec.md 의 문장 하나씩을 담은 벡터 열두 개를 docs/audio-ws-vectors/ 에, /api/audio 의 REST 벡터 셋을 docs/rest-api-vectors/ 에 두고, Node 20 에서 도는 WebSocket 보내는 쪽과 그것으로 벡터를 가상 패널에 돌리는 check:audio-vectors 를 더했다. 머지되면 CI 가 PR 마다 오디오 WebSocket 계약을 가상 패널에 돌려 보고, 스펙 문장이 바뀌면 그 문장을 옮긴 벡터가 빨개진다.

좋아지는 것: 없음

할 일

  • 계획서 PR 20 행(k20)과 D7~D12, docs/contract-vectors.md, _vectors.ts, PR 19([DONE] 정리 4단계 PR 19 — 가상 패널이 오디오 WebSocket 으로 레인을 잡고 놓으며, /api/audio 로 AUD 스위치를 켜고 끈다 #84)의 「for another k」를 읽는다
  • web/scripts/drift/_ws.ts: Node 20 에서 도는 WebSocket Sender, 벡터마다 소켓 하나
  • web/scripts/drift/audio-vectors.ts: replay("docs/audio-ws-vectors", { ws })
  • docs/audio-ws-vectors/: README 와 벡터 열둘
  • docs/rest-api-vectors/audio-*.json 셋
  • 300줄 안: +294
  • 일부러 깨뜨린 실행 넷(펌웨어처럼, 전송 버그, DeviceSim 규칙, REST 와 스펙 문장), 되돌림. 열다섯 벡터가 모두 한 번 이상 빨개졌다
  • 스무 번 연달아, 4코어에 여덟 개씩 나란히 세 번(24번). 다 통과
  • typecheck, lint, check:drift, 링크, 잠금, 글투, markers, doc-map
  • 이 PR 의 CI: 536bb0b 에서 Drift checks(PF_DRIFT_STRICT=1, passed audio-vectors)와 Docs point at files that exist 가 success
  • 「Web CI / build」도 536bb0b 에서 success
  • dev merge 한 번: PR 15([DONE] 정리 4단계 PR 15 — 가상 패널이 RTP-MIDI 세션을 받고 CC, 노트, Program Change 를 노브와 버튼, 패턴에 옮긴다 #83, 78b4538, tools/virtual-panel/transports/midi.ts 하나)가 들어왔다(58de9d8). 충돌 없음. typecheck, lint, check:drift, 링크, 잠금, 글투, audio·rest 벡터 다섯 번씩 다시 통과
  • 58de9d8 의 CI: Drift checks(116526590493, PF_DRIFT_STRICT=1 로 passed audio-vectors), Docs point at files that exist(116526590119), Web CI(116526588679) 셋 다 success
  • [DONE] 직전 dev 를 다시 받아 본다: 78b4538 그대로라 merge 할 것이 없다

한 일

_ws.ts 는 _vectors.ts 에 넘기는 ws Sender 다. CI 의 Node 20 에는 WebSocket 클라이언트가 없어서 node:http 의 upgrade 위에 RFC 6455 를 보내는 쪽만큼 짰다(D2, 의존성 없음). 핸드셰이크 뒤 Sec-WebSocket-Accept 를 키와 맞춰 보고, 보내는 프레임은 다 마스크한다(PR 19: 마스크 없는 프레임은 1002 로 닫힌다). 벡터의 ws 는 프레임 하나의 글이고, { "close": 1000 } 은 그 코드의 close 프레임이다. 패널이 보낸 텍스트 프레임은 heard 에 넣는다. 스펙은 패널이 아무것도 보내지 않는다고 한다.

settle() 은 ping 을 보내고 pong 을 기다린다. 패널은 프레임을 받은 순서대로 읽으므로, pong 이 오면 그 앞에 보낸 메시지는 다 패널의 inbox 에 있다. setImmediate 몇 번에 기대지 않는다. 2초 안에 답이 없으면 그 벡터가 「threw」로 빨개진다. close 도 패널의 close 프레임이 돌아올 때까지 기다린다.

벡터는 스펙의 절로 이름을 나눈다. 패널은 프레임 끝에 받은 것을 읽어서 레인은 20 ms, d= 는 그다음 프레임에 패턴에 닿아 50 ms 를 준다.

벡터 says 보는 것
messages-a A literal - in a slot … (27행) a=0.25,0.5,0.75,1 뒤 a=0.8,-,-,0.2 면 lanes 가 [0.8,0.5,0.75,0.2], 400 ms 뒤 - 였던 둘만 놓인다. a=-0.5,0.25,-,- 는 둘째 레인이 0.25, 셋째와 넷째는 그대로
messages-k Set lane N (0..3) to F (clamped …) (28행) k=0,v=0.25, k=2,v=1.5, k=3,v=-2 → lanes [0.25,_,1,0], laneActive [T,F,T,T]
messages-d Add a normalized delta … (29행) d=1,v=0.5 → 패턴이 받은 delta [0,24,0,0], 레인은 잡지 않는다. d=1,v=-0.25, d=3,v=-1 뒤 [0,12,0,-48]
messages-off-n Release knob N … (30행) 넷을 잡고 off=2 → 셋째만, off=0 → 첫째도 놓인다
messages-off Release all four. (31행) 넷을 잡고 off → 넷 다 놓인다
messages-unknown Anything else is silently ignored … (33행) 넷을 잡은 뒤 x=1, k=4,v=0.5, d=4,v=1, off=x, hello → 레인 그대로, delta 0. 그다음 k=1,v=0 은 먹는다
lanes-hand A physical turn of an encoder … (48행) K1 을 손으로 돌리면 첫 레인이 놓이고, 둘째 노브의 d= 는 둘째 레인을 놓지 않는다. 4760 ms 에 다시 보내도 첫 레인은 손의 것이고, 5060 ms 에 돌아온다
lanes-bus Priority per knob, highest first … (40행) POST /api/params?p1=700 뒤 다시 보낸 a= 에도 첫 레인은 놓이고 버스가 잡는다
lanes-close the firmware also releases lanes when the socket closes (51행) 넷을 잡고 audioClients 1, close 1000 뒤 넷 다 놓이고 audioClients 0
release-500ms A lane is handed back … 500 ms … (71행) contract-vectors.md 의 예시 그대로. 400 ms 엔 [T,F,F,T], 600 ms 엔 넷 다 놓인다
release-resend So a client that means to keep driving resends … (81행) 250 ms 마다 다시 보내면 첫 메시지 733 ms 뒤에도 잡혀 있고, 멈추면 놓인다
switch-off Switched off, the messages are parsed … (122행) on=0 이면 잡힌 레인이 바로 놓이고 audioRuntime false. 꺼진 동안 a= 와 d= 는 레인도 delta 도 없고 소켓은 열려 있다(audioClients 1). on=1 뒤 k= 가 먹는다

REST 벡터 셋, /api/audio 다. rest-vectors.ts 에는 WebSocket Sender 가 없어 소켓 없이 돈다.

벡터 says 보는 것
audio-caps A feature's endpoints exist only when … (613행) caps 가 ["patterns","params","sleep","audio"], GET /api/audio 는 JSON 200. 기본 빌드 쪽은 PR 7 의 absent-* 가 본다
audio-get audioRuntime (the switch) and audioClients … (488행) audioRuntime 은 boolean, 소켓이 없으니 audioClients 0
audio-post on=0/1. Persisted in NVS; answers with the new state. (489행) 쿼리 on=0 과 폼 on=1 의 답이 {"ok":true,"audioRuntime":…} 로 새 상태고, 다음 GET 도 같다

README 는 이름 머리, 메시지를 적는 법, 20 ms 와 50 ms 의 까닭, 「normalized」를 읽은 법, 펌웨어와 다른 셋, 다시 돌리지 않는 것을 적는다(D11).

증거

로컬, web/:

$ git diff --stat origin/dev...HEAD
 docs/audio-ws-vectors/README.md             | 13 +++++
 docs/audio-ws-vectors/lanes-bus.json        | 12 +++++
 docs/audio-ws-vectors/lanes-close.json      | 11 ++++
 docs/audio-ws-vectors/lanes-hand.json       | 17 ++++++
 docs/audio-ws-vectors/messages-a.json       | 15 ++++++
 docs/audio-ws-vectors/messages-d.json       | 12 +++++
 docs/audio-ws-vectors/messages-k.json       | 11 ++++
 docs/audio-ws-vectors/messages-off-n.json   | 13 +++++
 docs/audio-ws-vectors/messages-off.json     | 11 ++++
 docs/audio-ws-vectors/messages-unknown.json | 17 ++++++
 docs/audio-ws-vectors/release-500ms.json    | 11 ++++
 docs/audio-ws-vectors/release-resend.json   | 14 +++++
 docs/audio-ws-vectors/switch-off.json       | 16 ++++++
 docs/rest-api-vectors/audio-caps.json       |  9 ++++
 docs/rest-api-vectors/audio-get.json        |  8 +++
 docs/rest-api-vectors/audio-post.json       | 11 ++++
 web/scripts/drift/_ws.ts                    | 83 +++++++++++++++++++++++++++++
 web/scripts/drift/audio-vectors.ts          | 10 ++++
 18 files changed, 294 insertions(+)

$ npm run check:audio-vectors
docs/audio-ws-vectors/lanes-bus.json: same
docs/audio-ws-vectors/lanes-close.json: same
docs/audio-ws-vectors/lanes-hand.json: same
docs/audio-ws-vectors/messages-a.json: same
docs/audio-ws-vectors/messages-d.json: same
docs/audio-ws-vectors/messages-k.json: same
docs/audio-ws-vectors/messages-off-n.json: same
docs/audio-ws-vectors/messages-off.json: same
docs/audio-ws-vectors/messages-unknown.json: same
docs/audio-ws-vectors/release-500ms.json: same
docs/audio-ws-vectors/release-resend.json: same
docs/audio-ws-vectors/switch-off.json: same
passed   audio-vectors

$ npm run check:rest-vectors
docs/rest-api-vectors/audio-caps.json: same
docs/rest-api-vectors/audio-get.json: same
docs/rest-api-vectors/audio-post.json: same
docs/rest-api-vectors/{absent,device,mqtt,patterns,state}-*.json: same   (앞 PR 들의 마흔하나, 그대로)
passed   rest-vectors

$ for i in $(seq 1 20); do npx tsx scripts/drift.ts audio-vectors; done
passed 20 failed 0 in 34356 ms          # tsx 를 띄우는 것까지 한 번에 1.7초
# 4코어에 여덟 개씩 나란히 세 번: exit 0 이 24번

깨뜨린 넷. 각각 git checkout 으로 되돌렸고, 되돌린 뒤 passed.

  1. audio-ws.ts 를 펌웨어처럼: a= 의 칸이 - 로 시작하면 건너뛰고 나머지를 다음 칸으로 읽고(core_audio_ws.h:126), off=x 를 off=0 으로(163), d= 의 클릭을 sim.nudge 대신 sim.turn 으로(patternflow.ino:1333 처럼 손으로 친다).
docs/audio-ws-vectors/lanes-hand.json: drift
  only in the vector: step 05 status.laneActive[1] true, step 08 status.laneActive[1] true
  only in the panel: step 05 status.laneActive[1] false, step 08 status.laneActive[1] false
docs/audio-ws-vectors/messages-a.json: drift
  only in the vector: step 08 status.lanes[1] 0.25, step 08 status.lanes[2] 0.75
  only in the panel: step 08 status.lanes[1] 0.5, step 08 status.lanes[2] 0.25
docs/audio-ws-vectors/messages-unknown.json: drift
  only in the vector: step 08 status.laneActive[0] true
  only in the panel: step 08 status.laneActive[0] false
failed   audio-vectors                  # 나머지 아홉은 same
  1. audio-ws.ts 의 버그 다섯: k= 를 자르지 않고, d= 의 배율을 반으로, off=N 이 반대쪽 레인을 놓고 off 는 아무것도 놓지 않고, 꺼진 동안에도 메시지가 레인을 쓰고, 닫힌 소켓이 레인을 놓지 않는다.
lanes-close: drift      step 04 laneActive [F,F,F,F] ← [T,T,T,T]
messages-d: drift       deltas[1] 24 ← 12, deltas[1] 12 ← 6, deltas[3] -48 ← -24
messages-off-n: drift   step 04 [_,T,F,_] ← [_,F,T,_], step 06 [F,T,F,T] ← [T,F,T,F]
messages-off: drift     step 04 laneActive [F,F,F,F] ← [T,T,T,T]
switch-off: drift       step 06 deltas[0] 0 ← 12, step 09 laneActive[1..3] false ← true
failed   audio-vectors

(벡터 ← 패널로 줄였다.) messages-k 는 이 판에서 통과했다. DeviceSim.setLane 도 0..1 로 자르기 때문이다. 셋째 번에 그것까지 빼니 빨개졌다.

  1. deviceSim.ts(되돌림): setLane 이 자르지 않고, 레인을 700 ms 에 놓고, 손이 4초만 잡고, 버스가 레인 위에 있지 않다. audio-ws.ts 의 k= 자르기도 뺐다.
lanes-bus: drift        step 05 laneActive[0] false ← true
lanes-hand: drift       step 08 laneActive[0] false ← true
messages-a: drift       step 06 laneActive[1], [2] false ← true
messages-k: drift       step 04 lanes[2] 1 ← 1.5, lanes[3] 0 ← -2
release-500ms: drift    step 04 laneActive[0], [3] false ← true
release-resend: drift   step 07 laneActive[0] false ← true
failed   audio-vectors
  1. REST 와 스펙: GET /api/audio 의 audioClients 에 1 을 더하고, POST 가 바뀌기 전 상태로 답하고, caps 에서 audio 를 빼고, audio-ws-spec.md 48행의 「five seconds」를 「three seconds」로.
docs/rest-api-vectors/audio-caps.json: drift
  only in the vector: step 01 reply.body.caps ["patterns","params","sleep","audio"]
  only in the panel: step 01 reply.body.caps ["patterns","params","sleep"]
docs/rest-api-vectors/audio-get.json: drift
  only in the vector: step 01 reply.body.audioClients 0
  only in the panel: step 01 reply.body.audioClients 1
docs/rest-api-vectors/audio-post.json: drift
  only in the vector: step 01 reply.body.audioRuntime false, step 03 reply.body.audioRuntime true
  only in the panel: step 01 reply.body.audioRuntime true, step 03 reply.body.audioRuntime false
failed   rest-vectors
docs/audio-ws-vectors/lanes-hand.json: drift
  only in the vector: says docs/audio-ws-spec.md
  only in the panel: says not in docs/audio-ws-spec.md
failed   audio-vectors
$ npm run typecheck                     # exit 0
$ npm run lint -- --max-warnings=0      # exit 0
$ npm run check:drift
passed audio-vectors, bom, bom-schematic, changelog, editions, features, links-absolute, markers, mqtt-vectors, osc-vectors, presets, rest-vectors, shared, virtual-panel · skipped roadmap(원래 레포를 못 읽는다, CI 는 strict 로 통과)
$ python3 ../.github/scripts/check_links.py
all 729 relative links resolve
$ npm run check:human-lock
check:human-lock: no locked words changed
$ npm run check:voice
read: 106 added lines in 3 files
check:voice: nothing found
$ npx tsx scripts/drift.ts markers
passed   markers
$ git fetch --tags && npm run doc-map           # CSV 는 git checkout 으로 되돌렸다
1115 links from 223 files → docs/investigations/2026-10-doc-map.csv
0 do not resolve
1366 Korean/English pairs → docs/investigations/2026-10-doc-parity.csv
7 en-short, 18 ko-short, 1 missing-ko, 1340 ok

doc-map 의 새 줄은 넷이고 다 닿는다. docs/audio-ws-vectors/README.md 에서 docs/audio-ws-spec.md, docs/contract-vectors.md, docs/rest-api-vectors/README.md, tools/virtual-panel/README.md 로.

GitHub, 이 PR: 536bb0b 에서 「Drift checks / check」(job 116522245422) 로그에 PF_DRIFT_STRICT=1 로 passed audio-vectors, passed rest-vectors, passed roadmap, check:human-lock: no locked words changed. CI 의 Node 는 20 이라 _ws.ts 가 그 위에서 돈 것이다. 「Docs point at files that exist / check」(116522241840)와 「Web CI / build」(116522242354)도 success.

dev 의 PR 15 를 merge 한 58de9d8 에서 로컬로 다시:

$ npm run typecheck                     # exit 0
$ npm run lint -- --max-warnings=0      # exit 0
$ npm run check:drift
passed audio-vectors, bom, bom-schematic, changelog, editions, features, links-absolute, markers, mqtt-vectors, osc-vectors, presets, rest-vectors, shared, virtual-panel · skipped roadmap
$ python3 ../.github/scripts/check_links.py
all 729 relative links resolve
$ npm run check:human-lock && npm run check:voice
check:human-lock: no locked words changed
check:voice: nothing found
$ check:audio-vectors, check:rest-vectors 다섯 번씩    # 10/10 passed

panel.ts 는 transports/ 의 파일을 다 불러오므로, 이 실행은 midi.ts 가 불러와진 채로 돌았다. GitHub 에서도 58de9d8 의 「Drift checks / check」(116526590493) 로그에 passed audio-vectors, passed rest-vectors, passed roadmap 이 찍혔고, 「Docs point at files that exist」(116526590119)와 「Web CI / build」(116526588679)가 success 다.

실행법

cd web && npm ci
npm run check:audio-vectors
npm run check:rest-vectors

벡터 하나를 고쳐 보려면 docs/audio-ws-vectors/ 의 JSON 을 고치고 같은 명령을 돌린다.

가정

  • 기준 브랜치는 dev(머리말). 표가 PR 20 에 적은 docs/audio-ws-vectors/, docs/rest-api-vectors/audio-*.json, _ws.ts, audio-vectors.ts 만 더했다. CHANGELOG.md, docs/rfc-cleanup-progress.md, doc-map CSV, web/package.json(PR 2 가 check:audio-vectors 를 이미 넣었다), contract-vectors.md, _vectors.ts, tools/virtual-panel/ 는 안 고쳤다. 라벨은 앞 PR 들처럼 달지 않았다.
  • 계획서가 적은 것(- 칸이 있는 a=, 잘리는 k=, d=, off=N 과 off, 모르는 머리, 500 ms 뒤 놓이고 다시 보내면 남는 레인, 손이 5초 잡는 레인, audioRuntime 이 꺼진 동안 무시되는 메시지)에 둘을 더했다. 버스가 레인 위라는 것(lanes-bus)과 소켓이 닫히면 레인을 놓는 것(lanes-close)이다. 둘 다 스펙의 문장이고 가상 패널이 이미 그렇게 한다.
  • 300줄 안에 들이려고 둘을 뺐다. 「The device sends nothing」은 가상 패널이 텍스트 프레임을 보내는 길이 아예 없어 빨개질 수 없다. d= 가 레인을 붙잡아 두지 않는 것(PR 19 의 다섯째 issue)은 기기에서 따로 보이지 않는다. 한 클릭 이상의 d= 는 아래 셋째 issue 대로 그 노브를 5초 잡아 버리고, 반 클릭이 안 되는 d= 에서만 드러난다.
  • 벡터는 Audio-React 를 먼저 켜지 않는다. 새 가상 패널은 NVS 가 빈 기기처럼 켜진 채 시작하고(PR 19), README 가 그렇게 적는다. 스펙은 처음 값을 말하지 않는다. 실제 기기를 걷는 일은 이 단계가 아니다(질문 29). release-500ms 만 contract-vectors.md 의 예시라 POST /api/audio?on=1 로 시작한다.
  • 「normalized delta」를 parameter 의 전체 범위에 대한 몫으로 읽었다. 그 범위를 rest-api.md 382행이 48 detent 로 적는다(「48 detents cross a parameter's entire declared range」). 그래서 messages-d 는 0.5 를 24 클릭으로 본다. 값은 0.5, 0.25, 1 처럼 48 을 곱해 딱 떨어지는 것만 써서, 스펙이 말하지 않는 반올림에 기대지 않는다.
  • { "close": code } 는 contract-vectors.md 의 표(「A message is the frame's text」)에 없는 꼴이다. 그 문서는 PR 3 의 파일이고 _vectors.ts 는 얼어 있어, Sender 와 이 폴더 README 에만 적었다. 소켓이 하나라 「last write wins」와 다른 소켓이 열린 채 하나가 닫히는 경우는 벡터가 없다(README).
  • messages-a 의 a=-0.5,… 단계는 첫 레인 값을 "<number>" 로만 본다. 스펙은 a= 의 범위 밖 값을 어떻게 하는지 말하지 않는다(k= 만 「clamped」). 보는 것은 둘째 칸이 둘째 레인이고 - 칸이 손대지 않는다는 것이다.
  • audio-post 는 「Persisted in NVS」를 보지 않는다. 가상 패널에는 다시 켜는 일이 없다.
  • 스크린샷은 없다. 화면이 바뀌는 PR 이 아니다.
  • firmware/ 와 web/src/ 를 건드리지 않아 build.sh all, check:ci, check:panels 는 §2.1(1) 대상이 아니다. 계획서대로 typecheck 와 이 PR 의 check, 깨뜨린 실행을 적었다.

Changelog

Tools

  • The audio WebSocket has contract vectors. docs/audio-ws-vectors/ holds twelve, each one sentence of docs/audio-ws-spec.md and the messages that show a panel doing it, from a= with - slots to a lane a hand holds for five seconds. Three more in docs/rest-api-vectors/ read GET and POST /api/audio. npm run check:audio-vectors in web/ replays them against the virtual panel built with the audio feature, through a WebSocket client that runs on Node 20, and CI runs it with the other drift checks.

for an issue

D9. 벡터는 스펙을 따르고, 펌웨어는 셋에서 다르다.

  • messages-a.json step 07, 08 · audio-ws-spec.md 27, "A literal - in a slot leaves that lane untouched" · core_audio_ws.h:126 이 - 로 시작하는 칸을 건너뛰고 나머지를 다음 칸으로 읽는다. a=-0.5,0.25,-,- 는 둘째 레인에 0.5, 셋째에 0.25 를 둔다.
  • messages-unknown.json step 06, 08 · audio-ws-spec.md 30 과 33, off=N 과 "Anything else is silently ignored" · core_audio_ws.h:163 이 strtol 로 off=x 를 off=0 으로 읽어 첫 레인을 놓는다.
  • lanes-hand.json step 04, 05 · audio-ws-spec.md 48, "A physical turn of an encoder takes that knob back" · patternflow.ino:1333 이 노브의 delta 면 무엇이든 5초 잡기를 건다. 12 클릭이 되는 d=1,v=0.25 가 둘째 레인을 놓는다. 질문 28 의 경우다.

PR 19 가 적은 나머지 둘은 벡터가 없다. 마지막 클라이언트가 나갈 때만 레인을 놓는 것(core_audio_ws.h:182)은 소켓이 둘 있어야 보이고, d= 가 레인의 시간을 찍는 것(99)은 위 가정대로 기기에서 따로 보이지 않는다.

for another k

  • k21: AGENTS.md 의 audio-ws-spec.md 옆에 docs/audio-ws-vectors/, 명령에 check:audio-vectors.
  • k22: docs/README.md 의 audio-ws-spec.md 줄에 audio-ws-vectors/ 를, pfst 줄처럼. docs/contract-vectors.md 는 k22 의 목록에 없지만, 그 표의 ws 칸에 { "close": code } 를 적을 자리다.
  • k23: 이 PR 에서 나온 것은 없다.

Upstream

  • What: Add docs/audio-ws-vectors/, twelve vectors of docs/audio-ws-spec.md and a README, three REST vectors for GET and POST /api/audio, and check:audio-vectors, which replays them against the virtual panel through a WebSocket sender in web/scripts/drift/_ws.ts.
  • Checks: npm run typecheck, npm run lint and npm run check:drift (audio-vectors and rest-vectors included) pass; firmware/ and web/src/ are untouched.
  • Docs map: four new rows from docs/audio-ws-vectors/README.md, all resolving.

🤖 Generated with Claude Code

https://claude.ai/code/session_01M9se1jvH1i5Sc12oaN2xSW

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M9se1jvH1i5Sc12oaN2xSW
@patternflow-bot patternflow-bot changed the title [WIP] 정리 4단계 PR 20 [WIP] 정리 4단계 PR 20 — 오디오 WebSocket 벡터가 가상 패널에서 돌고, check:audio-vectors 가 PR 마다 본다 Oct 15, 2026
Twelve vectors of docs/audio-ws-spec.md and three REST vectors of
/api/audio, replayed against the virtual panel through a WebSocket
sender Node 20 can run.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M9se1jvH1i5Sc12oaN2xSW
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M9se1jvH1i5Sc12oaN2xSW
@patternflow-bot patternflow-bot changed the title [WIP] 정리 4단계 PR 20 — 오디오 WebSocket 벡터가 가상 패널에서 돌고, check:audio-vectors 가 PR 마다 본다 [DONE] 정리 4단계 PR 20 — 오디오 WebSocket 벡터가 가상 패널에서 돌고, check:audio-vectors 가 PR 마다 본다 Oct 15, 2026
@patternflow-bot
patternflow-bot marked this pull request as ready for review October 15, 2026 16:08
@patternflow-bot
patternflow-bot merged commit 30e14de into dev Oct 15, 2026
3 checks passed
@patternflow-bot
patternflow-bot deleted the claude/cleanup-step4-pr20-nwprtu branch October 15, 2026 16:12
engmung pushed a commit to engmung/Patternflow that referenced this pull request Oct 15, 2026
engmung pushed a commit to engmung/Patternflow that referenced this pull request Oct 15, 2026
Patternflow-lab#11
Patternflow-lab#12
Patternflow-lab#13
Patternflow-lab#15
Patternflow-lab#17
Patternflow-lab#14
Patternflow-lab#16
Patternflow-lab#19
Patternflow-lab#20
Patternflow-lab#18
Patternflow-lab#21
Patternflow-lab#23
Patternflow-lab#24
Patternflow-lab#25
Patternflow-lab#26
Patternflow-lab#28
Patternflow-lab#29
Patternflow-lab#30
Patternflow-lab#27
Patternflow-lab#31
Patternflow-lab#32
Patternflow-lab#34
Patternflow-lab#35
Patternflow-lab#33
Patternflow-lab#36
Patternflow-lab#37
Patternflow-lab#38
Patternflow-lab#39
Patternflow-lab#40
Patternflow-lab#41
Patternflow-lab#42
Patternflow-lab#43
Patternflow-lab#46
Patternflow-lab#44
Patternflow-lab#47
Patternflow-lab#48
Patternflow-lab#49
Patternflow-lab#45
Patternflow-lab#50
Patternflow-lab#51
Patternflow-lab#52
Patternflow-lab#54
Patternflow-lab#57
Patternflow-lab#55
Patternflow-lab#53
Patternflow-lab#56
Patternflow-lab#59
Patternflow-lab#58
Patternflow-lab#60
Patternflow-lab#61
Patternflow-lab#62
Patternflow-lab#63
Patternflow-lab#64
Patternflow-lab#65
Patternflow-lab#66
Patternflow-lab#67
Patternflow-lab#68
Patternflow-lab#69
Patternflow-lab#70
Patternflow-lab#72
Patternflow-lab#73
Patternflow-lab#71
Patternflow-lab#75
Patternflow-lab#74
Patternflow-lab#77
Patternflow-lab#78
Patternflow-lab#76
Patternflow-lab#79
Patternflow-lab#80
Patternflow-lab#81
Patternflow-lab#82
Patternflow-lab#84
Patternflow-lab#83
Patternflow-lab#85
Patternflow-lab#86
Patternflow-lab#87
Patternflow-lab#88
Patternflow-lab#90
Patternflow-lab#91
Patternflow-lab#89
Patternflow-lab#92
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants