fix(setup): 실험대를 새로 세워 setup 35편을 밟고 어긋난 명령과 결과를 고친다

기반 가이드 7단계로 실험대를 철거하고 다시 세운 뒤 virtualization setup 9편과
keycloak-session-store 26편을 순서대로 밟았다. 24편은 끝까지, 11편은 되는 데까지
밟았고 밟은 범위를 편마다 적었다.

명령이 못 도는 것을 고쳤다.

- kubectl 을 `kc-lab-1` 에서 치라고 적었는데 그 기계에 kubeconfig 가 없다.
  라벨 639개와 각 편의 「어디서 치는가」를 `[lab host]` 로 옮겼다
- `-o custom-columns=…[0]…` 이 zsh 에서 글로브로 읽혀 안 돈다. 28곳에 따옴표
- busybox `sed` 가 끝 개행을 안 붙여 A-3 의 측정이 언제나 0 이었다
- `--token-file ~/node-token` 뒤에 그 파일을 지우면 k3s agent 가 재부팅을
  못 견딘다. `/etc/rancher/node-token` 으로 옮기는 처방을 재서 넣었다
- 게스트에 없는 도구를 전제로 한 명령 넷 — `conntrack`·`dig`·`strings`·`nginx -v`
- `echo` 와 JWT 헤더가 `"이름" : [ 값 ]` 으로 찍는데 문서는 공백 없이 옮겨 적어
  그 실측으로 만든 grep·sed 가 한 줄도 못 잡는다
- B-0 이 `directAccessGrantsEnabled` 와 계정 완성을 빠뜨려 B-3 이 못 돈다
- D-4·D-4a 가 `test-server` 와 `certbot-renew.*` 를 가리키는데 실제로는
  `kc-lab-edge` 의 `certbot.service` 다
- `virsh setmaxmem --config` 를 `dominfo` 로 판정하면 틀린다. `--inactive` 로
- `LIBVIRT_DEFAULT_URI` 를 rc 에만 넣으면 `ssh host '명령'` 에서 안 먹는다

결과가 조건부인 것을 갈랐다.

- readiness 는 즉시 안 뒤집힌다. A-1·A-2 의 60초 창을 적었다
- 03 의 층 ②③ `301` 은 04 이후의 값이고 그 단계에서는 `404` 다
- A-0 의 로그 필터를 요청 직후에 치면 정반대 결론이 나온다
- A-5 의 한 방향 차단은 잠깐 `1` 이었다 `2` 로 돌아온다

증거는 두 프로젝트의 `evidence/raw/` 에 99벌을 README 와 함께 남겼다. 비밀은
길이만 적었고 화면에 찍힌 토큰은 가렸다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
DongHyeonka
2026-09-17 15:59:42 +09:00
co-authored by Claude Opus 5
parent ab59130196
commit 024362d096
197 changed files with 8336 additions and 960 deletions
@@ -114,31 +114,49 @@ while (cur < want) { // 모자라면 더한다
const labels = await fs.locator('label span').allInnerTexts();
```
## 칸 DOM 이 두 가지다
## 칸은 `aria-label` 로 찾는다 (2026-09-17 에 다시 잼)
위 xpath 는 절반만 통한다. 실제 편집 화면에는 모양이 둘이다.
```html
<label class="studio-field"><span>문제</span><textarea></textarea></label> <!-- A -->
<div class="studio-field"><label for="studio-field-summary">요약</label>
<textarea id="studio-field-summary"></textarea></div> <!-- B -->
```
`요약` · `본문 Markdown` · `관계 N 이유` 가 B형이다. A형만 찾으면 이 칸들이 조용히 안 채워진다.
**둘 다 본다.**
**위의 `label` 두 모양 이야기는 낡았다.** 지금 `label.studio-field` 가 감싸는 것은 제목과 요약
둘뿐이고, 나머지 칸은 전부 `aria-label` 을 갖는다. xpath 로 `span` 을 뒤질 일이 없다.
```js
async function field(page, name) {
const a = page.locator(`xpath=//label[./span[normalize-space(.)="${name}"]]`)
.locator('textarea, input').first();
if (await a.count()) return a;
const id = await page.locator(`xpath=//label[normalize-space(.)="${name}"]`)
.first().getAttribute('for');
return id ? page.locator('#' + id) : null;
}
document.querySelector('input[aria-label="제목"]')
document.querySelector('textarea[aria-label="요약"]')
document.querySelector('input[aria-label="slug"]')
document.querySelector('input[aria-label="판단 기준 1 제목"]')
document.querySelector('textarea[aria-label="적용할 때 3"]')
```
**본문 칸의 이름은 `본문` 이 아니라 `본문 Markdown` 이다.**
되풀이 칸을 늘리는 버튼은 `+ 판단 기준` · `+ 적용할 때` · `+ 예외와 주의` · `+ 예시` ·
`+ 버전 추가` 다. 줄 수를 먼저 맞추고 값을 넣는 규칙은 그대로다.
## 본문 칸이 사라졌다 — 블록 편집기다
**`본문 Markdown` 이라는 textarea 는 더 없다.** 본문은 `.studio-block-editor` 이고 블록 하나가
`<textarea>` 하나다. 기록 한 편이 블록 171개인 것을 실제로 봤다.
```
.studio-block-editor
├ textarea.studio-markdown-source 본문 전체의 거울. display:none · aria-hidden · readonly
├ .studio-block-editor__blocks
│ └ .studio-authoring-block[data-kind] heading · paragraph · code · bullet · raw
└ button + 블록 추가
```
**코드 블록의 `input.studio-code-language` 에 울타리 뒤 정보 문자열 전체가 들어간다**
`bash label="[kc-lab-1] ① 기동 로그에서 쿠키 설정을 찾는다"` 가 그 입력의 값이었다. 라벨을
넣을 별도 칸은 없다.
합성한 `ClipboardEvent` 로 붙여넣는 것은 **안 먹는다.** 그래서 쓰인 기록을 화면으로 옮기지
않는다 — [studio-api.md](studio-api.md) 의 `PUT` 으로 `bodyMarkdown` 을 통째로 보낸다.
`.studio-markdown-source``readonly` 라 입력 자리가 아니지만, 화면이 지금 무엇을 직렬화할지를
그대로 보여 주므로 **저장 전에 눈으로 대조하기에 좋다.**
## 저장 다음은 게시가 아니라 검증이다
편집 화면의 `aside` 에는 `저장``게시` 둘뿐인데, 저장만 된 기록은 서버가 `nextAction`
**`VALIDATE`** 로 준다. 검증 화면은 `/studio/documents/{id}/validation` 이다. 이 스킬은 저장까지라
거기까지 가지 않는다 — 다만 「저장했는데 왜 게시가 안 되나」의 답이 이것이다.
## Asset 을 올릴 때