raw — 명령 출력 원문 (정본)
===================

이 폴더가 증거의 정본이다. SVG 는 표현물이고 여기 원문 없이는 만들지 않는다.

파일 이름은 <실험 폴더>__<원본 파일명> 이다. 원본 저장소에서는 실험마다
폴더가 나뉘어 있었고 파일명이 겹쳤다(01-baseline.txt 등). 이 저장소의 감사
스크립트는 raw/ 최상위만 훑으므로 이름을 평평하게 펴고 접두사로 구분했다.

각 파일의 실행 메타는 ../meta/<같은 이름>.json 에 있다.
명령 전문은 그 json 의 sourceDoc 이 가리키는 해설 문서의 「재현 절차」 절에 있다.


[a1-jgroups-transport-block]
  a1-jgroups-transport-block__01-baseline-cluster.txt
      차단 전 — 양쪽이 뷰 ID 5·멤버 2로 일치, JGROUPS_PING 코디네이터 1명
  a1-jgroups-transport-block__02-control-before-block.txt
      대조군 — 차단 전 교차 노드 refresh 200, JGroups 지표 전부 0
  a1-jgroups-transport-block__03-block-applied.txt
      NetworkPolicy 적용. 빈 측정값을 "변화 감지"로 오판한 기록
  a1-jgroups-transport-block__04-after-block-state.txt
      차단 43초 후 — 지표 무변화, JGROUPS_PING 그대로
  a1-jgroups-transport-block__05-conntrack-problem.txt
      핵심 문제 — ESTABLISHED [ASSURED] 로 기존 연결이 살아 있음. FD_SOCK2 의 57800 포트도 함께 드러남
  a1-jgroups-transport-block__06-partition-observed.txt
      임시 curl 파드 폴링의 실패 — 빈 값·개수 불일치
  a1-jgroups-transport-block__07-cluster-size.txt
      vendor_cluster_size 가 25분 내내 2 — 분단이 일어나지 않았다는 결정적 증거
  a1-jgroups-transport-block__08-restart-forced-partition.txt
      재연결 강제 후 2 → 1
  a1-jgroups-transport-block__09-cross-node-under-partition.txt
      본 시험 — 교차 refresh 200(예측 적중), 로그아웃 후 재갱신 200(예측 빗나감)
  a1-jgroups-transport-block__10-logout-not-propagated.txt
      기제 확정 — DB 행 0건인데 keycloak-0 캐시에 1건, 헬스체크 cluster health: DOWN
  a1-jgroups-transport-block__11-service-impact.txt
      분단 노드가 Service 에서 빠짐. ready=[10.42.0.35] notReady=[10.42.1.67], 외부 로그인 200
  a1-jgroups-transport-block__12-recovery.txt
      90초 만에 자동 재형성, merge3_get_num_merge_events = 1, 코디네이터 재선출

[a2-database-loss]
  a2-database-loss__01-baseline.txt
      정지 전 — 양쪽 Ready, cluster_size=2
  a2-database-loss__02-setup-sessions.txt
      양쪽 노드에 세션 하나씩. 캐시는 각자 노드에만
  a2-database-loss__03-four-paths.txt
      네 경로 전부 500. 캐시를 가진 노드도 실패 — refresh 는 쓰기다
  a2-database-loss__04-health-and-service.txt
      전면 장애 증거 — Ready 파드 0개, ready 주소=[], 외부 503, database connections: DOWN. JWKS·.well-known 은 200
  a2-database-loss__05-recovery.txt
      up=1 인 채로 503. DB 복귀 15초 후 재시작 0회로 자동 회복, 세션 5건 생존

[a3-database-crash]
  a3-database-crash__01-crash-injection.txt
      첫 시도 실패 — 파드 안 백그라운드 루프가 exec 종료와 함께 죽어 0건 수집
  a3-database-crash__02-design-check.txt
      핵심 설계 확인 — 로그인 트랜잭션도 SET LOCAL synchronous_commit TO OFF 로 커밋한다
  a3-database-crash__03-loss-measurement.txt
      --grace-period=0 --force 주입
  a3-database-crash__04-comparison.txt
      유실 0건 — 그러나 crash recovery 가 안 돌았다. 죽인 적이 없는 것
  a3-database-crash__05-true-crash.txt
      kill -9 1 시도 — 컨테이너 안에서 PID 1 은 SIGKILL 을 무시한다
  a3-database-crash__06-backend-kill-crash.txt
      성공한 주입 — 백엔드에 SIGKILL → not properly shut down / redo starts / redo done
  a3-database-crash__07-loss-result.txt
      결과: 153건 중 4건 유실. 토큰은 발급됐는데 세션 행이 없는 sid 목록
  a3-database-crash__08-wal-settings.txt
      (원본 README 에 설명이 없다 — 파일 머리말 참조)

[a4-node-loss]
  a4-node-loss__01-baseline.txt
      차단 전 — 양쪽 Ready, PVC 가 kc-lab-2 에 못박혀 있음(재배치 불가의 원인), 외부 200
  a4-node-loss__02-worker-node-killed.txt
      virsh destroy kc-lab-2 — 40초간 노드가 Ready 로 남아 있고 외부는 이미 000. 이후 503
  a4-node-loss__03-state-during-loss.txt
      죽은 파드가 ready=true, 산 파드가 ready=false. up 은 정확히 0. unreachable taint
  a4-node-loss__04-eviction-timing.txt
      tolerationSeconds=300 — 5분 뒤 축출, 새 postgres 는 Pending
  a4-node-loss__05-recovery.txt
      FailedScheduling: didn't match PersistentVolume's node affinity, StatefulSet DESIRED=2 CURRENT=1. 노드 복귀 후 60초
  a4-node-loss__06-control-plane-inventory.txt
      kc-lab-1 에 있는 것 목록 — Traefik replicas=1
  a4-node-loss__07-control-plane-loss.txt
      virsh destroy kc-lab-1 — 외부 000, kubectl 불통. 그런데 crictl ps 로 보면 keycloak-0 은 Running
  a4-node-loss__08-control-plane-recovery.txt
      60초 만에 복귀

[a5-asymmetric-partition]
  a5-asymmetric-partition__01-injection.txt
      첫 시도 — iptables -I FORWARD 1
  a5-asymmetric-partition__02-injection-verify.txt
      실패 확인 — kube-router 가 자기 체인을 위로 재삽입, DROP 규칙 0 패킷
  a5-asymmetric-partition__03-raw-table-injection.txt
      raw 테이블로 이동. 그래도 0 패킷
  a5-asymmetric-partition__04-correct-direction.txt
      연결 방향이 반대였다. 수신측 노드로 옮기니 19/21 패킷 차단
  a5-asymmetric-partition__05-reconnect-observed.txt
      핵심 — 연결이 열린 방향으로 뒤집혀 재연결. 뷰 변화 없음, suspected=0
  a5-asymmetric-partition__06-view-history-and-cleanup.txt
      뷰 ID 이력. 주입 이후 변화 없음 확인
  a5-asymmetric-partition__07-bidirectional-block.txt
      양방향 차단 → 뷰 14, 멤버 1개씩. 그런데 ready=[10.42.1.77] 로 한쪽은 남고 외부 200
  a5-asymmetric-partition__08-coordinator-and-recovery.txt
      15] (2)

[a6-latency-injection]
  a6-latency-injection__01-baseline.txt
      배치 설명(A/B 가 되는 이유), agroal_* 지표 목록, 기준선 70ms / 66ms
  a6-latency-injection__02-delay-injected.txt
      첫 시도 실패 — Cannot find device "eth0" (Debian 은 enp1s0)
  a6-latency-injection__03-flannel-injection.txt
      성공 — flannel.1 에 걸어야 파드 IP 가 보인다. netem Sent 150 pkt 로 검증. k0=41ms vs k1=1872ms
  a6-latency-injection__04-pool-under-load.txt
      동시 20건 — 응답이 1.9초에서 22.2초까지 계단. blocking_time_max=20000ms, max_used_count=19, readiness 프로브 타임아웃
  a6-latency-injection__05-recovery.txt
      해제 즉시 43ms / 51ms 회복. 낙관적 락 충돌 0건(예측 빗나감)

[a7-volatile-comparison]
  a7-volatile-comparison__01-switch-to-volatile.txt
      --features-disabled=persistent-user-sessions 적용, args 확인
  a7-volatile-comparison__02-a0-rerun.txt
      DB 0건인데 교차 노드 refresh 200 — 경로가 DB 에서 클러스터로 바뀌었다
  a7-volatile-comparison__03-a8-rerun-restart.txt
      롤링 재시작 후 400 Session not active — persistent 에서는 200 이었다
  a7-volatile-comparison__04-a1-rerun-partition.txt
      7800 차단 시 교차 노드 400 — persistent 에서는 200. 대조군(같은 노드)은 200 유지
  a7-volatile-comparison__05-a2-rerun-db-loss.txt
      DB 정지 중 새 로그인 200(persistent 에서는 500), refresh 는 500
  a7-volatile-comparison__06-restore-persistent.txt
      원복 확인 — args: ["start"], 로그인 후 DB 1건, 외부 200

[a7a-volatile-cause]
  a7a-volatile-cause__01-cause-determined.txt
      가설이 틀렸다. REVOKED_TOKEN 이 아니라 CLIENT_SCOPE_CLIENT 조회다. 문장 로깅으로 잡고, 실패 로그가 그 SQL 을 직접 지목한다. 그리고 같은 설정에서 캐시 온도만으로 400/500/200 셋이 나온다

[a8-rolling-restart]
  a8-rolling-restart__01-restart-availability.txt
      재시작 전 로그인(sid 기록), 롤링 재시작 중 외부 진입점 9회 모두 200
  a8-rolling-restart__02-session-survival.txt
      재시작 전 토큰으로 refresh 200, DB 행 생존(last_session_refresh 갱신 확인), 세션 수 151 → 151, 캐시 0으로 초기화, 파드 나이 44초/66초

[b0-bff-redis-deploy]
  b0-bff-redis-deploy__01-deploy.txt
      배포 전 자원, Redis·BFF 롤아웃, 두 노드에 하나씩 배치됨
  b0-bff-redis-deploy__02-autoconfiguration.txt
      첫 조회 시도(파싱 실패)와 외부 진입점 HTTP 200
  b0-bff-redis-deploy__03-beans-analysis.txt
      B-0 의 답 — InMemoryOAuth2AuthorizedClientService, AuthenticatedPrincipalOAuth2AuthorizedClientRepository, Redis·Spring Session 없음

[b1-redis-session-store]
  b1-redis-session-store__01-servicelinks-trap.txt
      enableServiceLinks: false 적용 후 롤아웃 성공 — 쿠버네티스가 주입한 REDIS_PORT=tcp://... 가 설정을 덮어쓴 문제
  b1-redis-session-store__02-autoconfig-after.txt
      핵심 — 빈 321→402(+81). sessionRepository → RedisSessionRepository 로 바뀌었지만 authorizedClientService 는 InMemory 그대로
  b1-redis-session-store__03-redis-contents.txt
      Redis 키 1개, 필드는 SPRING_SECURITY_CONTEXT 뿐. 토큰 없음. Java 직렬화(\xac\xed), TTL 1772초

[b2-multi-instance-session]
  b2-multi-instance-session__01-jdbc-store-deploy.txt
      JDBC 저장소로 배포. 테이블이 조용히 안 만들어졌다
  b2-multi-instance-session__02-schema.txt
      원인 — 기본 DDL 은 blob(PostgreSQL 에 없음), -postgres.sql 판본이 따로 있다. PRIMARY KEY (client_registration_id, principal_name) — 조회 키 문제가 DDL 에 박혀 있다
  b2-multi-instance-session__03-plaintext-tokens.txt
      Q3 검증 2번 — bytea 안이 JWT 문자열 그대로. 디코드하면 {"alg":"HS512",...}
  b2-multi-instance-session__04-overwrite-test.txt
      Q1 검증 3번 — 같은 사용자 재로그인 시 행 수 1 그대로, issued_at 과 md5 만 바뀜 = UPDATE(덮어쓰기)
  b2-multi-instance-session__05-logout-cleanup.txt
      Q1 검증 4번 — Redis 0키 / PostgreSQL 1행 잔존 / Keycloak SSO 2세션 잔존

[b3-refresh-contention]
  b3-refresh-contention__01-concurrent-refresh.txt
      같은 토큰으로 동시 5회 — 1개만 200, 나머지는 Maximum allowed refresh token reuse exceeded 와 Session doesn't have required client 두 종류 오류
  b3-refresh-contention__02-session-impact.txt
      ★ 이긴 요청의 새 토큰조차 400. user_session 행은 남아 있고 revoked_token 은 0건
  b3-refresh-contention__03-client-session-removed.txt
      기제 확정 (대조군 포함) — 경쟁 세션 client_sessions=0, 정상 세션 client_sessions=1
  b3-refresh-contention__04-policy-comparison.txt
      정책 3종 비교 — rotation OFF 는 5/5 성공·세션 생존, maxReuse=1 은 여전히 세션 파괴

[b4-edge-authorization]
  b4-edge-authorization__01-header-handling.txt
      ① 동명 헤더가 둘 다 도착(['admin','editor'])하고 값 안의 쉼표를 구분자와 구별할 수 없다 · ② 8KB 에서 Tomcat 400, 16KB 에서 연결 끊김 — 자르지 않고 거부 · ④ 위조 신원 헤더가 그대로 도착, JWT 경로는 401

[b5-redis-loss]
  b5-redis-loss__01-baseline.txt
      정지 전 — Redis 1키, PostgreSQL 1행, save/appendonly no, 외부 200
  b5-redis-loss__02-redis-down.txt
      정지 후 — /bff/token-boundary HTTP 000(멈춤), /actuator/health 503, 파드는 1/1 Ready 유지, Lettuce 재연결 스택
  b5-redis-loss__03-health-groups.txt
      핵심 — /actuator/health 503 인데 /actuator/health/readiness 는 {"status":"UP"}. Service 엔드포인트에 두 파드 모두 남아 있다
  b5-redis-loss__04-persistence.txt
      복구는 자동(재시작 0회) · AOF 를 켰는데 파드 삭제 후 dbsize 0 · PVC 를 붙인 뒤 written-on-pvc 생존

[b6-key-rotation]
  b6-key-rotation__01-before-rotation.txt
      회전 전 — 토큰 kid=OY-caYDN..., JWKS RS256 1개, /api/me 200
  b6-key-rotation__02-rotation.txt
      우선순위 200 공급자 추가 → JWKS RS256 2개, 새 토큰은 새 kid, 옛 토큰도 새 토큰도 200 (무중단)
  b6-key-rotation__03-old-key-removed.txt
      옛 공급자 제거 → JWKS 1개, 옛 토큰 즉시 401. 리소스 서버 재시작 후에도 동일

[b7-cookie-secret]
  b7-cookie-secret__01-deploy.txt
      양 노드에 replica 하나씩. / 302, /ping 200
  b7-cookie-secret__02-cookie-portability.txt
      curl 로 흐름을 완주하려던 시도 — 파드 IP 는 호스트에서 안 닿는다
  b7-cookie-secret__03-rotation.txt
      --cookie-secret string 단수 확인 · 교체 후 session ticket cookie failed validation · Error removing session · Redis 에 고아 세션 2개

[b7a-orphan-session]
  b7a-orphan-session__01-orphan-lifecycle.txt
      회전 2회로 고아가 누적하는 것 · TTL 이 1초/초로 줄고 요청으로 갱신되지 않는 것 · Redis 만으로는 구분 불가(이름·타입·크기 동일, 값 암호화) · redis-cli del 로 지워도 산 세션은 200 · TTL 역산 정리 규칙이 1초 오차로 맞는 것

[c1-multi-app-sso]
  c1-multi-app-sso__01-baseline.txt
      초기화 시도 — logout-all 이 안 먹어 세션 4개가 남았다
  c1-multi-app-sso__02-after-app1-login.txt
      app1 로그인 후 — user session 1 · client session 1 · Redis 1 · DB 1행
  c1-multi-app-sso__03-after-app2-visit.txt
      app2 방문 후 client session 1 → 2, bff-confidential 과 oauth2-proxy 가 같은 user session 에 붙음. Redis 에 두 종류 세션
  c1-multi-app-sso__04-sso-session-killed.txt
      IdP 세션 삭제 후 — 앱 세션 셋 다 남아 있다. realm 을 join 해 보고서야 남은 것이 master 세션임을 확인

[c2-backchannel-logout]
  c2-backchannel-logout__01-current-state.txt
      두 클라이언트 모두 backchannelLogoutUrl 없음 · BFF 소스에 oidcLogout 없음 · 후보 경로 셋 다 302(핸들러 없음)
  c2-backchannel-logout__02-configure-idp.txt
      IdP 쪽에만 backchannel.logout.url 설정 (점 표기는 실패, JSON 으로 성공)
  c2-backchannel-logout__03-logout-attempt.txt
      살아 있는 세션(1)에 로그아웃 → IdP 세션 0, Redis 세션은 1 그대로. Keycloak·BFF 로그에 흔적 없음
  c2-backchannel-logout__04-reachability.txt
      Keycloak 파드가 app1.hyeonworks.com 에 HTTP 200 으로 닿는다 — 네트워크 문제가 아님

[d1-backup-restore]
  d1-backup-restore__01-backup.txt
      pg_dump --clean --if-exists — 395KB · 101 테이블 · 세션 데이터 포함
  d1-backup-restore__02-destruction.txt
      DROP SCHEMA public CASCADE → 테이블 0개. 그런데 외부는 HTTP 200 — Keycloak 이 realm 캐시로 서빙한다
  d1-backup-restore__03-restore.txt
      깨지는 것과 안 깨지는 것(certs 200 / well-known 500 / 토큰 400) · 복구 1초 · 오류 0건 · 데이터 완전 일치 · 재시작 0회

[d2-version-upgrade]
  d2-version-upgrade__01-pre-upgrade.txt
      백업 396KB · 이미지 26.7.0 · 마이그레이션 210건 · 세션 4
  d2-version-upgrade__02-rollback-attempt.txt
      26.0 으로 내리자 Running(0/1) → Error → CrashLoopBackOff. liquibase.exception.ValidationFailedException
  d2-version-upgrade__03-roll-forward.txt
      서비스는 HTTP 200 유지(ready 주소 1개) · 오류 원인 1 changesets check sum · 26.7.0 복귀 후 마이그레이션 210·세션 4 그대로

[d3-secret-management]
  d3-secret-management__01-base64-not-encryption.txt
      실험대의 모든 비밀이 명령 네 줄로 평문 출력. describe 는 14 bytes 만 보여줘 착각을 준다
  d3-secret-management__02-at-rest.txt
      Encryption Status: Disabled · state.db 안에 비밀번호 평문 2회 일치 · 파드 안에서는 KEYCLOAK_CLIENT_SECRET=bff-lab-secret 환경변수 · default SA 는 읽을 수 없음

[d4-certificate-renewal]
  d4-certificate-renewal__01-certificate-state.txt
      SAN 3개(와일드카드 아님) · 체인 4단계, Verify return code: 0 · certbot-renew.timer enabled·active, 11시간 전 실행 · 88일 남음 · sudo: a password is required 로 강제 갱신 불가
  d4-certificate-renewal__05-control-no-injection.txt
      대조군 1 — 잡음 바닥. 0.2초 × 900회 / 180초 동안 900 전부 200, 오류 0. 중앙 98ms · p95 195ms. TLS 핸드셰이크 900/900 = 매 요청이 새 연결
  d4-certificate-renewal__06-inflight-control.txt
      대조군 2 — '진행 중이던 요청' 장치. 845KB 를 --limit-rate 20k 로 받아 요청을 42초간 살려 둔다. 무주입 시 200 · 845361바이트 · 연결수 1
  d4-certificate-renewal__07-renewal-hook-missing.txt
      nginx 는 reload 된 적이 없다 — 마스터 585·워커 586 이 같은 시각 기동, 22.4시간째. 유닛은 ExecStart=certbot -q renew 가 전부. crt.sh 는 SCT 가 박힌 인증서를 0건으로 답한다
  d4-certificate-renewal__08-inflight-artifact.txt
      76건 실패는 서버 탓이 아니다 — 같은 순간 폴링 49건 전부 200, 연결수=0, 50µs, 재현 0/100. 대조군이 오보를 막았다
  d4-certificate-renewal__09-serial-timeline.txt
      일련번호 564표본. 08:10:51 ~ 08:58:47 옛 것 → 08:58:52 새 것
  d4-certificate-renewal__10-reload-poll-window.txt
      reload 전후 60초 새 연결 원문 — 비200 0건, 최대 373ms
  d4-certificate-renewal__11-inflight-full.txt
      in-flight 전체 50건. 08:58:40 시작 요청이 08:58:52 reload 를 관통해 845361바이트 전량 수신
  d4-certificate-renewal__12-certbot-state.txt
      cert2.pem 09-04 17:22:13 기록됨 · renewal-hooks/{deploy,post,pre}/ 셋 다 비었음 · 플러그인 목록에 nginx 없음
  d4-certificate-renewal__13-verdict.txt
      판정 전문 — 38분 25초 공백(428회 관측) + reload 무중단(8856건 0실패)

[d4a-deploy-hook]
  d4a-deploy-hook__01-hook-verified.txt
      판정 전문. 훅 실행 로그 · 워커 PID 교체 · 시계 보정과 SCT 교차검증 · D-4 와의 대조
  d4a-deploy-hook__02-certbot-with-hook.txt
      certbot renew --force-renewal 원문. Hook 'deploy-hook' ran 과 all renewals succeeded
  d4a-deploy-hook__03-after-state.txt
      실행 후 nginx 프로세스와 서빙 인증서

[followup]
  followup__01-d2-forward-upgrade.txt
      D-2 정방향 26.7.0 → 26.7.3. 백업 396KB · 87회 요청 전부 200(무중단) · 마이그레이션 210 → 210(스키마 변경 없음) · 세션 3 유지 · Infinispan 16.0.12 → 16.0.14
  followup__02-d2-rollback-same-schema.txt
      스키마가 안 바뀌면 롤백이 된다 — 26.7.3 → 26.7.0 성공. 다만 전환 순간 000 1회(3초 타임아웃)
  followup__03-b4-role-propagation.txt
      B-4 ③ IdP 에서 값을 바꿔도 12회 요청·6초 동안 옛 값. 세션 삭제 후 재인증에서야 새 값
  followup__04-observability-gap.txt
      B층에 관측이 없다 — Prometheus 는 keycloak·kubelet·node-exporter·prometheus 만 긁는다. Redis·BFF·PostgreSQL 지표가 0개
  followup__05-command-reproducibility.txt
      재현 절차 명령을 실제로 돌려본 기록. 산문이던 측정 장치를 셸 실행형으로 바꾼 뒤 실행 검증 — 4건 중 1건(동시 20건 부하)이 조용히 실패했고 상주 탐침 방식으로 고쳐 20/20 수집

[keycloak-multinode-cluster]
  keycloak-multinode-cluster__01-cluster-formed.txt
      파드 배치·클러스터 뷰 로그·JGROUPS_PING·OIDC discovery·자원

[session-replication]
  session-replication__01-cross-node-session.txt
      클러스터 2멤버 확인 → keycloak-0 로그인 → 같은 sid 가 양쪽에서 보임 → keycloak-1 이 refresh 성공(200) → keycloak-1 로그아웃 → keycloak-0 갱신 실패(400) → DB 행 삭제 확인
  session-replication__02-cache-delta.txt
      로그인 하나를 사이에 둔 양쪽 노드의 캐시 계수기. keycloak-1 은 전부 +0
  session-replication__03-cache-ownership.txt
      로그인을 반대편에 몰아준 결과. 요청을 받은 노드에서만 엔트리가 는다. 캐시 합 7+5 = DB 12
  session-replication__04-read-path-sql.txt
      PostgreSQL 문장 로깅으로 잡은 keycloak-1 이 실제로 날린 SQL. SELECT ... FROM OFFLINE_USER_SESSION 로 남의 세션을 읽고 UPDATE ... where VERSION=$5 로 쓴다. 같은 트랜잭션에 SET LOCAL synchronous_commit TO OFF 가 들어 있다

[two-hop-proxy-headers]
  two-hop-proxy-headers__01-environment.txt
      수정 전 세 계층의 설정 스냅샷
  two-hop-proxy-headers__02-measurements.txt
      수정 전 측정 · 대조 실험 · 위조 테스트 · 분배
  two-hop-proxy-headers__04-after-fix.txt
      최종 측정 · 위조 테스트 · 분배
  two-hop-proxy-headers__05-networkpolicy.txt
      (원본 README 에 설명이 없다 — 파일 머리말 참조)
