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:
co-authored by
Claude Opus 5
parent
ab59130196
commit
024362d096
@@ -367,6 +367,163 @@ Not `${NAME}` — guides use `$TOKEN`, `$SID` and friends as real shell
|
||||
variables, and a reader who reads a placeholder as one will paste it unchanged.
|
||||
`{{ }}` is not shell syntax, so pasting it fails where the reader can see it.
|
||||
|
||||
## The reader cannot see what is not on screen
|
||||
|
||||
Everything below came out of reading 35 finished guides in one pass. Each rule
|
||||
names the accident that produced it. None of them is a style preference — in
|
||||
every case the guide passed every other rule in this file and still handed the
|
||||
reader a wrong answer that looked right.
|
||||
|
||||
### A value copied into a container is a snapshot, not a reference
|
||||
|
||||
`kubectl run --env="K0=$K0"`, `docker run -e`, cloud-init user-data: each bakes
|
||||
the string as it was at that moment. From then on two spellings mean different
|
||||
things, and they differ by two characters:
|
||||
|
||||
```bash
|
||||
exec pod -- sh -c '...$K0...' # the value baked into the pod
|
||||
exec pod -- sh -c '...'"$K0"'...' # the value in the shell typing this
|
||||
```
|
||||
|
||||
**They agree until something restarts.** In one guide a `rollout restart` changed
|
||||
the pod IP, and a later step still read the baked copy; the request went to an
|
||||
address that no longer existed, and the failure it produced was a `500` — which
|
||||
was also that step's expected result. The screen looked correct.
|
||||
|
||||
So: when a step replaces the thing a baked value points at — a pod IP, a node
|
||||
address, a lease — say in that step which spelling the next commands use.
|
||||
Prefer recreating the container. If state inside it forbids that, show the
|
||||
live-read form and add one line saying why it differs from the block above.
|
||||
|
||||
**Distance is not the test.** A variable defined 700 lines up can be safe, and
|
||||
one defined nine lines up can be stale. Ask what happened in between.
|
||||
|
||||
### A step that only works inside a window says when, not just what
|
||||
|
||||
The four-part shape above — what / command / where to look / what it means —
|
||||
has no *when*. Several steps read correctly only during a restart, only while a
|
||||
rule is installed, only within sixty seconds. Read late, they do not error;
|
||||
they print a different, plausible number.
|
||||
|
||||
Name the command that opens the window and the one that closes it, and say
|
||||
**what the reader sees if they type it after it closed** — that is what most
|
||||
readers will actually get.
|
||||
|
||||
### A check must be able to fail
|
||||
|
||||
For every line that says "이렇게 나오면 통과", state what would print the same
|
||||
thing while the condition is false. Three real cases:
|
||||
|
||||
- `virsh list --all` used to prove a group membership took effect — it connects
|
||||
to the per-user URI, which works with no group at all
|
||||
- a `postmaster.pid` path checked on a fixed node, when the volume may be on the
|
||||
other one — "no such file" passes either way
|
||||
- `source ~/.bashrc` on a host whose login shell is zsh — true in that shell,
|
||||
gone at next login, and the symptom surfaces one guide later
|
||||
|
||||
If the check passes when the step was skipped — because it reads a different
|
||||
scope, host or shell than the step wrote to — it is not a check. Put the scope
|
||||
in the command, or write one line naming the failure this check cannot see.
|
||||
|
||||
### Never ship a command the guide knows is wrong
|
||||
|
||||
Three guides printed a command and told the reader, in prose underneath, to
|
||||
edit it before typing. Prose is not a guard. The worst of them was a **valid**
|
||||
assignment:
|
||||
|
||||
```bash
|
||||
OLDID=980ee9b7-... # ← copy from the output above
|
||||
```
|
||||
|
||||
Paste it and `OLDID` holds the literal string, and the `delete` two lines later
|
||||
runs. Every other hardcoded value in those guides failed loudly — `(0 rows)`,
|
||||
`(nil)`. This one succeeded at the wrong thing.
|
||||
|
||||
If prose under a block says "replace X first", the block already says it — or
|
||||
says `{{X}}`, which is not shell syntax and fails where the reader can see it.
|
||||
|
||||
### One block, one machine
|
||||
|
||||
A code block is the reader's copy unit. When the machine changes, the block
|
||||
ends, even when the commands form one logical step. Splitting the explanation
|
||||
in prose does not help: they copy the block.
|
||||
|
||||
And a machine label tells the reader *where* a block runs — it does not put
|
||||
them there. When consecutive blocks carry different labels, the transition is
|
||||
its own step with its own command (`ssh host`, `exit`, "open a second
|
||||
terminal"). Count them per guide: entries and exits must balance. A
|
||||
verification section that runs somewhere else needs both.
|
||||
|
||||
### A shell function defined mid-guide is worse than all three tiers
|
||||
|
||||
It leaves no file, so the reader cannot re-read it. It dies with the shell, so
|
||||
a new window silently breaks every later step. `unset` does not reach it.
|
||||
|
||||
One guide defined `R()` on line 188 and used it through line 617 — a one-letter
|
||||
name for `kubectl -n … exec deploy/redis -- redis-cli`. At the point of use
|
||||
the reader cannot see what command they are running.
|
||||
|
||||
If something is repeated often enough to want a name, make it a script file
|
||||
with that name. If it must be a function, define it in the same block as its
|
||||
first use, name it for what it does (`redis`, not `R`), and restate the
|
||||
definition at the top of any later section more than a screen away.
|
||||
|
||||
### Names the reader must already have
|
||||
|
||||
A host alias, a directory, a volume, a file that no earlier step created is not
|
||||
a placeholder — it is an assumption, and the placeholder rule above does not
|
||||
catch it. Four guides in one set ran entirely on `ssh kc-lab-1` with no stanza
|
||||
anywhere that creates it; the second guide hits it on its first command.
|
||||
|
||||
Show the command that creates it, or name the guide that owns it, in the prose
|
||||
above the first block that uses it.
|
||||
|
||||
### Walk the guide twice
|
||||
|
||||
`echo >>` is one case of a larger rule. Anything created under a fixed name — a
|
||||
pod, a volume, a DHCP reservation, a namespace — says what the second run
|
||||
prints and how to clear it first. `--rm` only removes on clean exit; Ctrl+C
|
||||
leaves the pod and the next run dies on `AlreadyExists`.
|
||||
|
||||
And anything that destroys and recreates a host says what identity changes with
|
||||
it — SSH host keys, MAC-bound leases, certificates — and what that breaks the
|
||||
next time the reader connects.
|
||||
|
||||
### The output block belongs to the command above it
|
||||
|
||||
If it came from a wider `grep`, an extra `uniq -c`, or a `sed` that rewrote
|
||||
names, show that command too or say so on the line before. Readers compare
|
||||
their screen to yours character by character; a silent edit makes them hunt for
|
||||
a fault that is not there.
|
||||
|
||||
### Context selectors are read as a set
|
||||
|
||||
`-n`, `--context`, `-h`, `-U`. One guide's `kubectl exec` was missing
|
||||
`-n keycloak-lab` while the eight commands around it had it. On its own the
|
||||
line looks fine; next to its neighbours it is obviously running somewhere else.
|
||||
Read them as a column, not line by line.
|
||||
|
||||
### When the same action has several forms, one of them is the step
|
||||
|
||||
One guide gave three ways to kill a backend and marked none of them. Show the
|
||||
step; put the rest under a heading that says they are alternatives. Leaving the
|
||||
reader to choose asks them to weigh a trade-off the guide has not explained yet.
|
||||
|
||||
### A fixed output path makes a block single-use
|
||||
|
||||
"Change the variable and run it again" is incomplete when the block writes to a
|
||||
fixed file: the second run overwrites the first run's baseline, silently, and
|
||||
the comparison two sections later has nothing to compare against. Name the
|
||||
output path among the things to change.
|
||||
|
||||
### Run the remedy you prescribe
|
||||
|
||||
A guide diagnosed lexical sorting and prescribed `sort -g`. Every line in that
|
||||
file began with the same `200`, so `sort -g` compared equal and fell through to
|
||||
byte order — its output was identical to plain `sort`. The fix the guide
|
||||
offered did not fix anything, and the sentence "miss this and you misread the
|
||||
maximum" stayed true after following it.
|
||||
|
||||
## Rationalization table
|
||||
|
||||
| Excuse | Reality |
|
||||
@@ -383,6 +540,11 @@ variables, and a reader who reads a placeholder as one will paste it unchanged.
|
||||
| "The file ends up the same either way" | Only on the first run. `echo >>` appends again every time someone repeats the guide |
|
||||
| "So I should use nano for everything" | No. The trigger is authoring a file the reader must understand. `grep`, `virsh`, a long `virt-install` stay as they are |
|
||||
| "`python3 -c` only checks syntax" | Then it misses the schema. If the format has a validator — `cloud-init schema`, `nginx -t`, `--dry-run` — that is the step |
|
||||
| "The prose right under it says to change that value" | The reader copies the block. Prose is not a guard — put `{{NAME}}` in the block |
|
||||
| "The variable is defined earlier in the same shell" | Ask what restarted in between. A pod IP baked at line 877 was stale by line 764 |
|
||||
| "The label says which machine it runs on" | A label says where, not how to get there. The transition is its own step |
|
||||
| "It's the same command, just shorter" | A one-letter function hides the command at the exact moment the reader needs to read it |
|
||||
| "The check passed" | Ask what it would print if the step had been skipped. Three checks in one set passed either way |
|
||||
|
||||
## Red flags — stop and rewrite
|
||||
|
||||
@@ -398,6 +560,14 @@ variables, and a reader who reads a placeholder as one will paste it unchanged.
|
||||
- one line stacking connect + redirect + file creation (`ssh host 'cat > f' < f`)
|
||||
- `python3 -c` checking syntax when the format has its own validator
|
||||
- a step that appends, so walking the guide twice appends the line twice
|
||||
- prose under a block telling the reader to edit the command before typing it
|
||||
- a block whose machine label differs from the one above, with no command between
|
||||
- a one- or two-letter shell function, or any function defined far from its use
|
||||
- a host alias, directory or volume that no step in any guide creates
|
||||
- `--rm` with no line saying what a Ctrl+C leaves behind
|
||||
- a "통과" line that would print the same thing if the step had been skipped
|
||||
- a step that reads correctly only during a window, with no word about the window
|
||||
- a remedy you have not run against the data that made you prescribe it
|
||||
|
||||
## References
|
||||
|
||||
|
||||
Reference in New Issue
Block a user