W23 · 운영 관측성

23주차 코드 뒤풀이: metric·requestId·DB wait부터 alert·runbook까지

낮은 cardinality metric 설계와 learner-typed Micrometer 코드에서 시작해, requestId 회귀 Gate·disposable PostgreSQL row-lock wait·행동 가능한 alert와 incident runbook까지 하나의 관측 사슬로 읽습니다. 로컬 자동 증거와 dashboard·notification 같은 외부 수동 증거를 분리하고, 교재의 stale 잠금 설명과 정본 source 차이, prompt-only Q37·Q38의 비정본 가정도 그대로 드러냅니다.

원문 정본 · 제공 incident runbook bytes 1개원문 정본 · 완전한 packaged PowerShell source 2개학습용 예시 · metric catalog template · 정본 답안 아님 1개학습용 예시 · 학습자 작성 Java · 정본 답안 아님 · 실행 결과 아님 2개학습용 예시 · claim registry · 정본 답안 아님 · 비실행 1개학습용 예시 · alert/runbook template · 정본 답안 아님 · 외부 미실행 2개학습용 예시 · Q37/Q38 prompt 기반 SQL · 정본 답안 아님 2개항목마다 13단계연결 361줄번역 361줄원문 PDF 751–784쪽
01

D1 metric catalog — RED와 도메인 신호 5개를 낮은 cardinality로 고정

illustrative/csv/W23-D1-metric-catalog.csv

학습용 예시 · metric catalog template · 정본 답안 아님 · 학습용 예시 · 정본 답안 아님 · W23-F01
6줄 연결6줄 번역1 chunks
01

STEP 01 / 13

오늘 이 코드에서 해결할 문제

무엇을 이해해야 하는지 질문부터 잡습니다.

오늘의 한 문장

RED 관점의 필수 metric 5개와 낮은 cardinality tag만 고정하는 D1 학습 catalog다.

  1. `metrics=5`은 어느 줄에서 생기거나 검증될까?
  2. 입력→guard→관찰→cleanup 또는 stable output 순서는 무엇인가?
  3. local 자동 owner와 external human owner는 각각 누구인가?
  4. 이 source가 직접 관찰하지 않은 Green은 무엇인가?
  5. 반례는 `catalog는 실제 meter 등록이나 dashboard를 증명하지 않는다` 경계와 어떻게 연결되는가?
이 파일에서 끝까지 다시 쓰는 값metrics=5required=5high_cardinality_tags=0rate/error/durationfixed outcome tags
02

STEP 02 / 13

아주 짧게: 이 코드는 왜 필요할까?

웹소설 대신 이 코드가 필요한 이유만 두 문단으로 쉽게 봅니다.

STARRY가 metric catalog·requestId 봉투·DB wait 영수증·alert/runbook·SQL grain 표를 서로 다른 칸에 놓는다.

D1 metric catalog — RED와 도메인 신호 5개를 낮은 cardinality로 고정 ― 관측 증거 흐름으로 바꾸기

RED 관점의 필수 metric 5개와 낮은 cardinality tag만 고정하는 D1 학습 catalog다.

핵심값 metrics=5, required=5, high_cardinality_tags=0, rate/error/duration, fixed outcome tags을 원본 줄로 따라가되, `catalog는 실제 meter 등록이나 dashboard를 증명하지 않는다`까지 함께 표시해 local 관찰을 외부 운영 Green으로 부풀리지 않는다.

딱 여기까지만 비유는 grain·owner·순서를 기억하게 할 뿐 실제 Gradle/Docker/PostgreSQL 실행, dashboard·notification, 운영 SLA를 자동 증명하지 않는다.

03

STEP 03 / 13

초등학생도 이해하는 설명

생활 비유와 실제 코드의 경계를 함께 확인합니다.

원문 1–6줄

1~6줄을 한 덩어리로 읽어 1번째 움직임을 본다. RED 관점의 필수 metric 5개와 낮은 cardinality tag만 고정하는 D1 학습 catalog다.

코드 연결
1~6줄
비유
관제실 계기판에 속도·고장·지연과 금고 이상 신호를 다섯 칸으로 나누고, 버튼 이름은 몇 개의 고정 선택지만 쓰는 계측표
비유의 끝
catalog는 실제 meter 등록이나 dashboard를 증명하지 않는다
문제의 첫 장면히토리 → 니지카 → 료 → 키타
  1. 히토리

    첫 고정값은 `metrics=5` 맞아?

  2. 니지카

    RED 관점의 필수 metric 5개와 낮은 cardinality tag만 고정하는 D1 학습 catalog다.

  3. 원문에서 `metrics=5`이 만들어지거나 확인되는 줄을 찾자.

  4. 키타

    그리고 `catalog는 실제 meter 등록이나 dashboard를 증명하지 않는다`도 같이 적어.

입력에서 결과까지히토리 → 니지카 → 료 → 키타
  1. 히토리

    `required=5`은 언제 생겨?

  2. 니지카

    고객 요청 RED 신호를 정한다. → transfer·retry 도메인 신호를 더한다.

  3. reconciliation·idempotency 이상 신호를 더한다. → 모든 tag가 LOW cardinality인지 검토한다.

  4. 키타

    관찰값과 `requestId·accountId를 metric tag로 쓰지 않는다`을 분리하면 돼.

04

STEP 04 / 13

비유 ↔ 코드 전체 연결표

감사 규칙상 연결 대상인 원본 6줄을 빠짐없이 연결합니다.

단어 몇 개만 뽑은 표가 아닙니다.학습용 예시 · metric catalog template · 정본 답안 아님에서 비어 있지 않은 모든 줄을 원본 줄 번호 그대로 연결했습니다.6 / 6 연결
정확한 원본 줄STARRY 비유실제 뜻·입력·결과·한계
1줄F01-L01 metric,type,tags,meaning,cardinality,alert_or_dashboard 관제실 계기판에 속도·고장·지연과 금고 이상 신호를 다섯 칸으로 나누고, 버튼 이름은 몇 개의 고정 선택지만 쓰는 계측표 metric 이름·meter type·허용 tag·의미·cardinality·사용처라는 catalog 열 계약을 연다.
입력
요청 RED·transfer·retry·대사·idempotency 관측 요구
결과·효과
이 줄 뒤에는 항목 전체의 `metrics=5` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
catalog는 실제 meter 등록이나 dashboard를 증명하지 않는다
2줄F01-L02 http_server_requests,timer,route|status|outcome,customer request rate error and duration,LOW,RED rate error and p95 dashboard 관제실 계기판에 속도·고장·지연과 금고 이상 신호를 다섯 칸으로 나누고, 버튼 이름은 몇 개의 고정 선택지만 쓰는 계측표 요청 rate·error·duration을 route/status/outcome의 제한된 tag로 관찰하는 RED timer다.
입력
요청 RED·transfer·retry·대사·idempotency 관측 요구
결과·효과
이 줄 뒤에는 항목 전체의 `required=5` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
requestId·accountId를 metric tag로 쓰지 않는다
3줄F01-L03 transfer_completed,counter,outcome,committed transfer outcomes by fixed category,LOW,transfer outcome dashboard 관제실 계기판에 속도·고장·지연과 금고 이상 신호를 다섯 칸으로 나누고, 버튼 이름은 몇 개의 고정 선택지만 쓰는 계측표 고정 outcome별 완료 건수를 누적하는 domain counter다.
입력
요청 RED·transfer·retry·대사·idempotency 관측 요구
결과·효과
이 줄 뒤에는 항목 전체의 `high_cardinality_tags=0` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
threshold는 운영 SLA가 아니다
4줄F01-L04 transfer_retry,counter,sqlstate_category,bounded database lock retry attempts,LOW,retry burst alert 관제실 계기판에 속도·고장·지연과 금고 이상 신호를 다섯 칸으로 나누고, 버튼 이름은 몇 개의 고정 선택지만 쓰는 계측표 SQLSTATE의 제한된 category별 lock retry 시도를 세는 counter다.
입력
요청 RED·transfer·retry·대사·idempotency 관측 요구
결과·효과
이 줄 뒤에는 항목 전체의 `rate/error/duration` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
외부 관측 UI는 별도 증거가 필요하다
5줄F01-L05 reconciliation_mismatch,gauge,job,unresolved reconciliation mismatch count,LOW,ledger mismatch alert 관제실 계기판에 속도·고장·지연과 금고 이상 신호를 다섯 칸으로 나누고, 버튼 이름은 몇 개의 고정 선택지만 쓰는 계측표 아직 해결되지 않은 대사 불일치 수를 job별로 읽는 gauge다.
입력
요청 RED·transfer·retry·대사·idempotency 관측 요구
결과·효과
이 줄 뒤에는 항목 전체의 `fixed outcome tags` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
catalog는 실제 meter 등록이나 dashboard를 증명하지 않는다
6줄F01-L06 idempotency_stale,gauge,operation,stale processing idempotency records,LOW,stale request alert 관제실 계기판에 속도·고장·지연과 금고 이상 신호를 다섯 칸으로 나누고, 버튼 이름은 몇 개의 고정 선택지만 쓰는 계측표 stale PROCESSING idempotency record 수를 operation별로 읽는 gauge다.
입력
요청 RED·transfer·retry·대사·idempotency 관측 요구
결과·효과
이 줄 뒤에는 항목 전체의 `metrics=5` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
requestId·accountId를 metric tag로 쓰지 않는다
Green 범위히토리 → 니지카 → 료 → 키타
  1. 히토리

    marker나 문서가 보이면 W23 전체 성공이야?

  2. 니지카

    아니. 이 source가 직접 검증한 claim만 말해야 해.

  3. 직접 연결되는 대표 값은 `fixed outcome tags`이야.

  4. 키타

    `threshold는 운영 SLA가 아니다`는 별도 실행·사람 증거가 필요해.

05

STEP 05 / 13

원본 코드 조각

원본을 1개 의미 조각으로 나누어 그대로 확인합니다.

파일을 한꺼번에 외우지 않고 실행 의미가 이어지는 작은 조각으로 봅니다. 아래 코드는 prompt·fixture·가정을 밝힌 학습용 예시 source이며, 제공 정본 답안이 아닙니다.

F01-C01 · 원문 1–6줄1–6줄
1–6줄 원본
metric,type,tags,meaning,cardinality,alert_or_dashboard
http_server_requests,timer,route|status|outcome,customer request rate error and duration,LOW,RED rate error and p95 dashboard
transfer_completed,counter,outcome,committed transfer outcomes by fixed category,LOW,transfer outcome dashboard
transfer_retry,counter,sqlstate_category,bounded database lock retry attempts,LOW,retry burst alert
reconciliation_mismatch,gauge,job,unresolved reconciliation mismatch count,LOW,ledger mismatch alert
idempotency_stale,gauge,operation,stale processing idempotency records,LOW,stale request alert
06

STEP 06 / 13

코드 한 줄씩 한국어로 번역

비어 있지 않은 6줄을 모두 한국어로 옮깁니다.

전체 번역 6 / 6

비어 있지 않은 원본 줄은 하나도 생략하지 않습니다.

원본한국어 번역
1metric,type,tags,meaning,cardinality,alert_or_dashboardmetric 이름·meter type·허용 tag·의미·cardinality·사용처라는 catalog 열 계약을 연다.
2http_server_requests,timer,route|status|outcome,customer request rate error and duration,LOW,RED rate error and p95 dashboard요청 rate·error·duration을 route/status/outcome의 제한된 tag로 관찰하는 RED timer다.
3transfer_completed,counter,outcome,committed transfer outcomes by fixed category,LOW,transfer outcome dashboard고정 outcome별 완료 건수를 누적하는 domain counter다.
4transfer_retry,counter,sqlstate_category,bounded database lock retry attempts,LOW,retry burst alertSQLSTATE의 제한된 category별 lock retry 시도를 세는 counter다.
5reconciliation_mismatch,gauge,job,unresolved reconciliation mismatch count,LOW,ledger mismatch alert아직 해결되지 않은 대사 불일치 수를 job별로 읽는 gauge다.
6idempotency_stale,gauge,operation,stale processing idempotency records,LOW,stale request alertstale PROCESSING idempotency record 수를 operation별로 읽는 gauge다.
07

STEP 07 / 13

기존 수준의 한 줄 읽기·문법 해부

쉬운 설명 다음에 문법과 실행 순서를 정밀하게 읽습니다.

한 줄로 읽기

RED 관점의 필수 metric 5개와 낮은 cardinality tag만 고정하는 D1 학습 catalog다. 다만 catalog는 실제 meter 등록이나 dashboard를 증명하지 않는다

문법 해부

  • CSV 첫 줄은 metric·type·tags·meaning·cardinality·사용처라는 여섯 열 계약이다.
  • `route|status|outcome`처럼 tag 후보를 제한하고 고객 ID·requestId 같은 무한 값을 tag로 쓰지 않는다.

실행 순서

  1. 고객 요청 RED 신호를 정한다.
  2. transfer·retry 도메인 신호를 더한다.
  3. reconciliation·idempotency 이상 신호를 더한다.
  4. 모든 tag가 LOW cardinality인지 검토한다.

W23 조각별 정밀 해설

F01-C01 · 원문 1–6줄
문법 해부
1~6줄의 `원문 1–6줄`을 입력·grain/guard·관찰·cleanup/stable output 단계로 나눈다.
실제 값 추적
항목 전체 흐름에 연결해 `metrics=5`을 대조한다. 이 값이 chunk 단독 산출이라는 뜻은 아니다.
정상 예
정상 예에서는 source 순서와 owner 계약이 일치해 `metrics=5`을 관찰한다.
틀린 예·반례
반례에서는 선행 guard·grain·stable order·cleanup을 생략한다. 동결 경계: catalog는 실제 meter 등록이나 dashboard를 증명하지 않는다.
착각 방지
`원문 1–6줄`이 항목 전체 또는 외부 운영 Green을 단독 증명한다고 읽지 않는다.
하지 않는 일
이 chunk가 책임지지 않는 범위: catalog는 실제 meter 등록이나 dashboard를 증명하지 않는다.
다음 연결
다음 source chunk의 입력 또는 exact local marker·SQL oracle·사람 검토 경계로 결과를 넘긴다.
반례히토리 → 니지카 → 료 → 키타
  1. 히토리

    겉보기에는 맞지만 깨지는 예는?

  2. 니지카

    requestId나 accountId를 metric tag로 넣는다

  3. 그 상태는 입력 grain·owner·관찰 중 한 칸이 비어 있어.

  4. 키타

    수정한 뒤 같은 source bytes와 evidence를 다시 대조해.

08

STEP 08 / 13

실제 값 따라가기

같은 입력값이 어느 줄을 지나 어떤 결과가 되는지 추적합니다.

순서들어온 값코드가 하는 일나온 값·상태경계
F01-T01 HTTProute/status/outcometimerrate·error·duration실제 dashboard 실행 아님
F01-T02 transfer고정 outcomecountercompleted/retry개별 고객 tag 금지
F01-T03 integrityjob/operationgaugemismatch·stalethreshold는 별도 검증
책임 경계히토리 → 니지카 → 료 → 키타
  1. 히토리

    이 항목의 마지막 책임선은?

  2. 니지카

    직접 역할은 `관측 metric 이름·type·tag cardinality 계약`이야.

  3. 대표 경계는 `외부 관측 UI는 별도 증거가 필요하다`이야.

  4. 키타

    정본/학습용 label과 local/external owner까지 확인하면 끝이야.

09

STEP 09 / 13

Micrometer·RequestId·PowerShell·PostgreSQL 내부에서 벌어지는 일

Micrometer·JUnit·PowerShell·PostgreSQL·alert/runbook에서 실제로 일어나는 일과 증명 범위를 구분합니다.

Micrometer registry

이름과 tag 조합별 meter를 보관한다.

catalog만으로 application 등록을 증명하지 않는다.
time-series backend

tag 조합마다 시계열을 만든다.

LOW 표시는 실제 cardinality 측정값이 아니다.
alert/dashboard

meter를 query와 window에 연결한다.

URL·screenshot이 없으면 external Green이 아니다.
10

STEP 10 / 13

흔한 착각과 틀린 예

그럴듯하지만 틀린 해석을 반례로 고칩니다.

❌ requestId나 accountId를 metric tag로 넣는다

왜 틀리나 관측 metric 이름·type·tag cardinality 계약의 grain·owner·관찰·경계 중 적어도 하나를 건너뛴다.

바르게 읽기 고객 요청 RED 신호를 정한다. 그리고 source의 실제 값과 provenance를 다시 대조한다.

반례 반례에서는 `catalog는 실제 meter 등록이나 dashboard를 증명하지 않는다` 상태인데도 Green을 주장하게 된다.

❌ counter와 gauge의 의미를 섞는다

왜 틀리나 관측 metric 이름·type·tag cardinality 계약의 grain·owner·관찰·경계 중 적어도 하나를 건너뛴다.

바르게 읽기 transfer·retry 도메인 신호를 더한다. 그리고 source의 실제 값과 provenance를 다시 대조한다.

반례 반례에서는 `requestId·accountId를 metric tag로 쓰지 않는다` 상태인데도 Green을 주장하게 된다.

❌ 5xx와 업무 409를 같은 오류율로 합친다

왜 틀리나 관측 metric 이름·type·tag cardinality 계약의 grain·owner·관찰·경계 중 적어도 하나를 건너뛴다.

바르게 읽기 reconciliation·idempotency 이상 신호를 더한다. 그리고 source의 실제 값과 provenance를 다시 대조한다.

반례 반례에서는 `threshold는 운영 SLA가 아니다` 상태인데도 Green을 주장하게 된다.

❌ catalog 5행을 dashboard 실행 증거라 부른다

왜 틀리나 관측 metric 이름·type·tag cardinality 계약의 grain·owner·관찰·경계 중 적어도 하나를 건너뛴다.

바르게 읽기 모든 tag가 LOW cardinality인지 검토한다. 그리고 source의 실제 값과 provenance를 다시 대조한다.

반례 반례에서는 `외부 관측 UI는 별도 증거가 필요하다` 상태인데도 Green을 주장하게 된다.

❌ threshold를 운영 SLA로 단정한다

왜 틀리나 관측 metric 이름·type·tag cardinality 계약의 grain·owner·관찰·경계 중 적어도 하나를 건너뛴다.

바르게 읽기 모든 tag가 LOW cardinality인지 검토한다. 그리고 source의 실제 값과 provenance를 다시 대조한다.

반례 반례에서는 `catalog는 실제 meter 등록이나 dashboard를 증명하지 않는다` 상태인데도 Green을 주장하게 된다.

11

STEP 11 / 13

이 코드가 보장하지 않는 것

이 코드가 책임지지 않는 일을 분리합니다.

직접 미보장

catalog는 실제 meter 등록이나 dashboard를 증명하지 않는다

이 책임을 맡는 곳: metric/query grain
직접 미보장

requestId·accountId를 metric tag로 쓰지 않는다

이 책임을 맡는 곳: 별도 local/external 실행
직접 미보장

threshold는 운영 SLA가 아니다

이 책임을 맡는 곳: secret·개인정보·운영 정책
직접 미보장

외부 관측 UI는 별도 증거가 필요하다

이 책임을 맡는 곳: infrastructure·사람 검토
12

STEP 12 / 13

직접 다시 써보기

뜻 → 조각 → 전체 코드 순서로 다시 씁니다.

1단계 · 뜻부터 복원

다음 역할을 고정값과 미보장 경계까지 말한다: RED 관점의 필수 metric 5개와 낮은 cardinality tag만 고정하는 D1 학습 catalog다.

2단계 · 코드 조각 재조립

  1. 원문 1–6줄

3단계 · 파일 전체 다시 쓰기

6개 물리 줄을 원본 순서로 복원하고 SHA-256 3b4d42f8d2037b67091c78d60d8159b10a4b75e8890e3b0e442d71f098fd089e와 대조한다.

자가 점검
  • 원본 source/template bytes와 줄 번호를 바꾸지 않았는가?
  • 정본 3개와 학습용 예시 8개를 구분했는가?
  • RequestId local Gate와 DB wait local drill의 Green 범위를 분리했는가?
  • dashboard·alert·incident timeline을 NOT_RUN_EXTERNAL 또는 사람 검토로 남겼는가?
  • Q37의 JOIN grain과 Q38의 SUCCESS·반개구간 가정을 드러냈는가?
13

STEP 13 / 13

전체 원본 source

감사로 고정한 전체 source를 가감 없이 확인합니다.

학습용 예시 전체 확인하기 · 정본 답안 아님
학습용 예시 · metric catalog template · 정본 답안 아님illustrative/csv/W23-D1-metric-catalog.csvSHA-256 3b4d42f8d2037b67091c78d60d8159b10a4b75e8890e3b0e442d71f098fd089e
D1 metric catalog — RED와 도메인 신호 5개를 낮은 cardinality로 고정 전체
metric,type,tags,meaning,cardinality,alert_or_dashboard
http_server_requests,timer,route|status|outcome,customer request rate error and duration,LOW,RED rate error and p95 dashboard
transfer_completed,counter,outcome,committed transfer outcomes by fixed category,LOW,transfer outcome dashboard
transfer_retry,counter,sqlstate_category,bounded database lock retry attempts,LOW,retry burst alert
reconciliation_mismatch,gauge,job,unresolved reconciliation mismatch count,LOW,ledger mismatch alert
idempotency_stale,gauge,operation,stale processing idempotency records,LOW,stale request alert
02

TransferMetrics.java — 성공·업무 거절 counter와 duration을 한 경계에서 기록

illustrative/java/TransferMetrics.java

학습용 예시 · 학습자 작성 Java · 정본 답안 아님 · 실행 결과 아님 · 학습용 예시 · 정본 답안 아님 · W23-F02
24줄 연결24줄 번역3 chunks
01

STEP 01 / 13

오늘 이 코드에서 해결할 문제

무엇을 이해해야 하는지 질문부터 잡습니다.

오늘의 한 문장

성공·업무 거절 outcome counter와 성공/실패 공통 duration timer를 기록하는 learner-typed Micrometer wrapper다.

  1. `fcl.transfer`은 어느 줄에서 생기거나 검증될까?
  2. 입력→guard→관찰→cleanup 또는 stable output 순서는 무엇인가?
  3. local 자동 owner와 external human owner는 각각 누구인가?
  4. 이 source가 직접 관찰하지 않은 Green은 무엇인가?
  5. 반례는 `reference project packaged production source가 아니다` 경계와 어떻게 연결되는가?
이 파일에서 끝까지 다시 쓰는 값fcl.transfercompletedbusiness_rejectedfcl.transfer.durationfinally stop
02

STEP 02 / 13

아주 짧게: 이 코드는 왜 필요할까?

웹소설 대신 이 코드가 필요한 이유만 두 문단으로 쉽게 봅니다.

STARRY가 metric catalog·requestId 봉투·DB wait 영수증·alert/runbook·SQL grain 표를 서로 다른 칸에 놓는다.

TransferMetrics.java — 성공·업무 거절 counter와 duration을 한 경계에서 기록 ― 관측 증거 흐름으로 바꾸기

성공·업무 거절 outcome counter와 성공/실패 공통 duration timer를 기록하는 learner-typed Micrometer wrapper다.

핵심값 fcl.transfer, completed, business_rejected, fcl.transfer.duration, finally stop을 원본 줄로 따라가되, `reference project packaged production source가 아니다`까지 함께 표시해 local 관찰을 외부 운영 Green으로 부풀리지 않는다.

딱 여기까지만 비유는 grain·owner·순서를 기억하게 할 뿐 실제 Gradle/Docker/PostgreSQL 실행, dashboard·notification, 운영 SLA를 자동 증명하지 않는다.

03

STEP 03 / 13

초등학생도 이해하는 설명

생활 비유와 실제 코드의 경계를 함께 확인합니다.

원문 1–10줄

1~10줄을 한 덩어리로 읽어 1번째 움직임을 본다. 성공·업무 거절 outcome counter와 성공/실패 공통 duration timer를 기록하는 learner-typed Micrometer wrapper다.

코드 연결
1~10줄
비유
택배 접수 때 성공·반려 도장을 찍고, 어느 출구로 나가도 스톱워치는 반드시 멈추게 만든 한 개의 계측 창구
비유의 끝
reference project packaged production source가 아니다

원문 11–20줄

11~20줄을 한 덩어리로 읽어 2번째 움직임을 본다. 성공·업무 거절 outcome counter와 성공/실패 공통 duration timer를 기록하는 learner-typed Micrometer wrapper다.

코드 연결
11~20줄
비유
택배 접수 때 성공·반려 도장을 찍고, 어느 출구로 나가도 스톱워치는 반드시 멈추게 만든 한 개의 계측 창구
비유의 끝
RuntimeException 전체를 업무 거절로 분류하면 운영 분류를 더 세분해야 한다

원문 21–28줄

21~28줄을 한 덩어리로 읽어 3번째 움직임을 본다. 성공·업무 거절 outcome counter와 성공/실패 공통 duration timer를 기록하는 learner-typed Micrometer wrapper다.

코드 연결
21~28줄
비유
택배 접수 때 성공·반려 도장을 찍고, 어느 출구로 나가도 스톱워치는 반드시 멈추게 만든 한 개의 계측 창구
비유의 끝
registry 구현과 export 설정은 별도다
문제의 첫 장면히토리 → 니지카 → 료 → 키타
  1. 히토리

    첫 고정값은 `fcl.transfer` 맞아?

  2. 니지카

    성공·업무 거절 outcome counter와 성공/실패 공통 duration timer를 기록하는 learner-typed Micrometer wrapper다.

  3. 원문에서 `fcl.transfer`이 만들어지거나 확인되는 줄을 찾자.

  4. 키타

    그리고 `reference project packaged production source가 아니다`도 같이 적어.

입력에서 결과까지히토리 → 니지카 → 료 → 키타
  1. 히토리

    `completed`은 언제 생겨?

  2. 니지카

    Timer.Sample을 시작한다. → action을 한 번 호출한다.

  3. 성공 또는 business_rejected counter를 올린다. → finally에서 duration timer를 멈춘다.

  4. 키타

    관찰값과 `RuntimeException 전체를 업무 거절로 분류하면 운영 분류를 더 세분해야 한다`을 분리하면 돼.

04

STEP 04 / 13

비유 ↔ 코드 전체 연결표

감사 규칙상 연결 대상인 원본 24줄을 빠짐없이 연결합니다.

단어 몇 개만 뽑은 표가 아닙니다.학습용 예시 · 학습자 작성 Java · 정본 답안 아님 · 실행 결과 아님에서 비어 있지 않은 모든 줄을 원본 줄 번호 그대로 연결했습니다.24 / 24 연결
정확한 원본 줄STARRY 비유실제 뜻·입력·결과·한계
1줄F02-L01 package com.example.financialcore.observability; 택배 접수 때 성공·반려 도장을 찍고, 어느 출구로 나가도 스톱워치는 반드시 멈추게 만든 한 개의 계측 창구 Micrometer transfer 계측 경계 학습 코드의 1번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
입력
MeterRegistry와 한 번 실행할 transfer Supplier<T>
결과·효과
이 줄 뒤에는 항목 전체의 `fcl.transfer` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
reference project packaged production source가 아니다
3줄F02-L03 import io.micrometer.core.instrument.MeterRegistry; 택배 접수 때 성공·반려 도장을 찍고, 어느 출구로 나가도 스톱워치는 반드시 멈추게 만든 한 개의 계측 창구 Micrometer meter를 등록하고 이름·tag로 다시 찾는 registry dependency다.
입력
MeterRegistry와 한 번 실행할 transfer Supplier<T>
결과·효과
이 줄 뒤에는 항목 전체의 `business_rejected` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
registry 구현과 export 설정은 별도다
4줄F02-L04 import io.micrometer.core.instrument.Timer; 택배 접수 때 성공·반려 도장을 찍고, 어느 출구로 나가도 스톱워치는 반드시 멈추게 만든 한 개의 계측 창구 Micrometer transfer 계측 경계 학습 코드의 4번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
입력
MeterRegistry와 한 번 실행할 transfer Supplier<T>
결과·효과
이 줄 뒤에는 항목 전체의 `fcl.transfer.duration` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
meter 등록만으로 dashboard Green이 아니다
5줄F02-L05 import java.util.Objects; 택배 접수 때 성공·반려 도장을 찍고, 어느 출구로 나가도 스톱워치는 반드시 멈추게 만든 한 개의 계측 창구 Micrometer transfer 계측 경계 학습 코드의 5번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
입력
MeterRegistry와 한 번 실행할 transfer Supplier<T>
결과·효과
이 줄 뒤에는 항목 전체의 `finally stop` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
reference project packaged production source가 아니다
6줄F02-L06 import java.util.function.Supplier; 택배 접수 때 성공·반려 도장을 찍고, 어느 출구로 나가도 스톱워치는 반드시 멈추게 만든 한 개의 계측 창구 Micrometer transfer 계측 경계 학습 코드의 6번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
입력
MeterRegistry와 한 번 실행할 transfer Supplier<T>
결과·효과
이 줄 뒤에는 항목 전체의 `fcl.transfer` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
RuntimeException 전체를 업무 거절로 분류하면 운영 분류를 더 세분해야 한다
8줄F02-L08 public final class TransferMetrics { 택배 접수 때 성공·반려 도장을 찍고, 어느 출구로 나가도 스톱워치는 반드시 멈추게 만든 한 개의 계측 창구 Micrometer transfer 계측 경계 학습 코드의 8번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
입력
MeterRegistry와 한 번 실행할 transfer Supplier<T>
결과·효과
이 줄 뒤에는 항목 전체의 `business_rejected` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
meter 등록만으로 dashboard Green이 아니다
9줄F02-L09 private final MeterRegistry registry; 택배 접수 때 성공·반려 도장을 찍고, 어느 출구로 나가도 스톱워치는 반드시 멈추게 만든 한 개의 계측 창구 Micrometer meter를 등록하고 이름·tag로 다시 찾는 registry dependency다.
입력
MeterRegistry와 한 번 실행할 transfer Supplier<T>
결과·효과
이 줄 뒤에는 항목 전체의 `fcl.transfer.duration` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
reference project packaged production source가 아니다
11줄F02-L11 public TransferMetrics(MeterRegistry registry) { 택배 접수 때 성공·반려 도장을 찍고, 어느 출구로 나가도 스톱워치는 반드시 멈추게 만든 한 개의 계측 창구 Micrometer meter를 등록하고 이름·tag로 다시 찾는 registry dependency다.
입력
MeterRegistry와 한 번 실행할 transfer Supplier<T>
결과·효과
이 줄 뒤에는 항목 전체의 `fcl.transfer` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
registry 구현과 export 설정은 별도다
12줄F02-L12 this.registry = Objects.requireNonNull(registry); 택배 접수 때 성공·반려 도장을 찍고, 어느 출구로 나가도 스톱워치는 반드시 멈추게 만든 한 개의 계측 창구 Micrometer transfer 계측 경계 학습 코드에서 `this.registry = Objects.requireNonNull(registry)` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
MeterRegistry와 한 번 실행할 transfer Supplier<T>
결과·효과
이 줄 뒤에는 항목 전체의 `completed` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
meter 등록만으로 dashboard Green이 아니다
13줄F02-L13 } 택배 접수 때 성공·반려 도장을 찍고, 어느 출구로 나가도 스톱워치는 반드시 멈추게 만든 한 개의 계측 창구 현재 object·array·block 또는 query 범위를 열거나 닫아 구조와 실행 순서를 유지한다.
입력
MeterRegistry와 한 번 실행할 transfer Supplier<T>
결과·효과
이 줄 뒤에는 항목 전체의 `business_rejected` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
reference project packaged production source가 아니다
15줄F02-L15 public <T> T record(Supplier<T> action) { 택배 접수 때 성공·반려 도장을 찍고, 어느 출구로 나가도 스톱워치는 반드시 멈추게 만든 한 개의 계측 창구 Micrometer transfer 계측 경계 학습 코드의 15번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
입력
MeterRegistry와 한 번 실행할 transfer Supplier<T>
결과·효과
이 줄 뒤에는 항목 전체의 `finally stop` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
registry 구현과 export 설정은 별도다
16줄F02-L16 Timer.Sample sample = Timer.start(registry); 택배 접수 때 성공·반려 도장을 찍고, 어느 출구로 나가도 스톱워치는 반드시 멈추게 만든 한 개의 계측 창구 동작 시작 시각을 잡아 성공·예외 공통 duration 기록의 출발점을 만든다.
입력
MeterRegistry와 한 번 실행할 transfer Supplier<T>
결과·효과
이 줄 뒤에는 항목 전체의 `fcl.transfer` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
meter 등록만으로 dashboard Green이 아니다
17줄F02-L17 try { 택배 접수 때 성공·반려 도장을 찍고, 어느 출구로 나가도 스톱워치는 반드시 멈추게 만든 한 개의 계측 창구 정상·실패 경로와 공통 cleanup/계측 경계를 분리하는 control-flow 블록이다.
입력
MeterRegistry와 한 번 실행할 transfer Supplier<T>
결과·효과
이 줄 뒤에는 항목 전체의 `completed` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
reference project packaged production source가 아니다
18줄F02-L18 T result = action.get(); 택배 접수 때 성공·반려 도장을 찍고, 어느 출구로 나가도 스톱워치는 반드시 멈추게 만든 한 개의 계측 창구 계측으로 감싼 실제 동작을 정확히 한 번 호출한다.
입력
MeterRegistry와 한 번 실행할 transfer Supplier<T>
결과·효과
이 줄 뒤에는 항목 전체의 `business_rejected` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
RuntimeException 전체를 업무 거절로 분류하면 운영 분류를 더 세분해야 한다
19줄F02-L19 registry.counter("fcl.transfer", "outcome", "completed").increment(); 택배 접수 때 성공·반려 도장을 찍고, 어느 출구로 나가도 스톱워치는 반드시 멈추게 만든 한 개의 계측 창구 성공 분기의 고정 outcome counter를 1 올린다.
입력
MeterRegistry와 한 번 실행할 transfer Supplier<T>
결과·효과
이 줄 뒤에는 항목 전체의 `fcl.transfer.duration` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
registry 구현과 export 설정은 별도다
20줄F02-L20 return result; 택배 접수 때 성공·반려 도장을 찍고, 어느 출구로 나가도 스톱워치는 반드시 멈추게 만든 한 개의 계측 창구 Micrometer transfer 계측 경계 학습 코드의 20번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
입력
MeterRegistry와 한 번 실행할 transfer Supplier<T>
결과·효과
이 줄 뒤에는 항목 전체의 `finally stop` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
meter 등록만으로 dashboard Green이 아니다
21줄F02-L21 } catch (RuntimeException rejected) { 택배 접수 때 성공·반려 도장을 찍고, 어느 출구로 나가도 스톱워치는 반드시 멈추게 만든 한 개의 계측 창구 Micrometer transfer 계측 경계 학습 코드의 21번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
입력
MeterRegistry와 한 번 실행할 transfer Supplier<T>
결과·효과
이 줄 뒤에는 항목 전체의 `fcl.transfer` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
reference project packaged production source가 아니다
22줄F02-L22 registry.counter("fcl.transfer", "outcome", "business_rejected").increment(); 택배 접수 때 성공·반려 도장을 찍고, 어느 출구로 나가도 스톱워치는 반드시 멈추게 만든 한 개의 계측 창구 RuntimeException 분기의 고정 거절 outcome counter를 1 올린다.
입력
MeterRegistry와 한 번 실행할 transfer Supplier<T>
결과·효과
이 줄 뒤에는 항목 전체의 `completed` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
RuntimeException 전체를 업무 거절로 분류하면 운영 분류를 더 세분해야 한다
23줄F02-L23 throw rejected; 택배 접수 때 성공·반려 도장을 찍고, 어느 출구로 나가도 스톱워치는 반드시 멈추게 만든 한 개의 계측 창구 선행 invariant가 깨졌을 때 evidence 발행 전에 멈추는 fail-closed guard다.
입력
MeterRegistry와 한 번 실행할 transfer Supplier<T>
결과·효과
이 줄 뒤에는 항목 전체의 `business_rejected` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
registry 구현과 export 설정은 별도다
24줄F02-L24 } finally { 택배 접수 때 성공·반려 도장을 찍고, 어느 출구로 나가도 스톱워치는 반드시 멈추게 만든 한 개의 계측 창구 Micrometer transfer 계측 경계 학습 코드의 24번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
입력
MeterRegistry와 한 번 실행할 transfer Supplier<T>
결과·효과
이 줄 뒤에는 항목 전체의 `fcl.transfer.duration` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
meter 등록만으로 dashboard Green이 아니다
25줄F02-L25 sample.stop(registry.timer("fcl.transfer.duration")); 택배 접수 때 성공·반려 도장을 찍고, 어느 출구로 나가도 스톱워치는 반드시 멈추게 만든 한 개의 계측 창구 finally 경로에서 성공·예외 모두 duration timer를 끝낸다.
입력
MeterRegistry와 한 번 실행할 transfer Supplier<T>
결과·효과
이 줄 뒤에는 항목 전체의 `finally stop` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
reference project packaged production source가 아니다
26줄F02-L26 } 택배 접수 때 성공·반려 도장을 찍고, 어느 출구로 나가도 스톱워치는 반드시 멈추게 만든 한 개의 계측 창구 현재 object·array·block 또는 query 범위를 열거나 닫아 구조와 실행 순서를 유지한다.
입력
MeterRegistry와 한 번 실행할 transfer Supplier<T>
결과·효과
이 줄 뒤에는 항목 전체의 `fcl.transfer` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
RuntimeException 전체를 업무 거절로 분류하면 운영 분류를 더 세분해야 한다
27줄F02-L27 } 택배 접수 때 성공·반려 도장을 찍고, 어느 출구로 나가도 스톱워치는 반드시 멈추게 만든 한 개의 계측 창구 현재 object·array·block 또는 query 범위를 열거나 닫아 구조와 실행 순서를 유지한다.
입력
MeterRegistry와 한 번 실행할 transfer Supplier<T>
결과·효과
이 줄 뒤에는 항목 전체의 `completed` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
registry 구현과 export 설정은 별도다
28줄F02-L28 } 택배 접수 때 성공·반려 도장을 찍고, 어느 출구로 나가도 스톱워치는 반드시 멈추게 만든 한 개의 계측 창구 현재 object·array·block 또는 query 범위를 열거나 닫아 구조와 실행 순서를 유지한다.
입력
MeterRegistry와 한 번 실행할 transfer Supplier<T>
결과·효과
이 줄 뒤에는 항목 전체의 `business_rejected` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
meter 등록만으로 dashboard Green이 아니다
Green 범위히토리 → 니지카 → 료 → 키타
  1. 히토리

    marker나 문서가 보이면 W23 전체 성공이야?

  2. 니지카

    아니. 이 source가 직접 검증한 claim만 말해야 해.

  3. 직접 연결되는 대표 값은 `finally stop`이야.

  4. 키타

    `registry 구현과 export 설정은 별도다`는 별도 실행·사람 증거가 필요해.

05

STEP 05 / 13

원본 코드 조각

원본을 3개 의미 조각으로 나누어 그대로 확인합니다.

파일을 한꺼번에 외우지 않고 실행 의미가 이어지는 작은 조각으로 봅니다. 아래 코드는 prompt·fixture·가정을 밝힌 학습용 예시 source이며, 제공 정본 답안이 아닙니다.

F02-C01 · 원문 1–10줄1–10줄
1–10줄 원본
package com.example.financialcore.observability;

import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Timer;
import java.util.Objects;
import java.util.function.Supplier;

public final class TransferMetrics {
    private final MeterRegistry registry;
F02-C02 · 원문 11–20줄11–20줄
11–20줄 원본
    public TransferMetrics(MeterRegistry registry) {
        this.registry = Objects.requireNonNull(registry);
    }

    public <T> T record(Supplier<T> action) {
        Timer.Sample sample = Timer.start(registry);
        try {
            T result = action.get();
            registry.counter("fcl.transfer", "outcome", "completed").increment();
            return result;
F02-C03 · 원문 21–28줄21–28줄
21–28줄 원본
        } catch (RuntimeException rejected) {
            registry.counter("fcl.transfer", "outcome", "business_rejected").increment();
            throw rejected;
        } finally {
            sample.stop(registry.timer("fcl.transfer.duration"));
        }
    }
}
06

STEP 06 / 13

코드 한 줄씩 한국어로 번역

비어 있지 않은 24줄을 모두 한국어로 옮깁니다.

전체 번역 24 / 24

비어 있지 않은 원본 줄은 하나도 생략하지 않습니다.

원본한국어 번역
1package com.example.financialcore.observability;Micrometer transfer 계측 경계 학습 코드의 1번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
3import io.micrometer.core.instrument.MeterRegistry;Micrometer meter를 등록하고 이름·tag로 다시 찾는 registry dependency다.
4import io.micrometer.core.instrument.Timer;Micrometer transfer 계측 경계 학습 코드의 4번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
5import java.util.Objects;Micrometer transfer 계측 경계 학습 코드의 5번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
6import java.util.function.Supplier;Micrometer transfer 계측 경계 학습 코드의 6번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
8public final class TransferMetrics {Micrometer transfer 계측 경계 학습 코드의 8번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
9 private final MeterRegistry registry;Micrometer meter를 등록하고 이름·tag로 다시 찾는 registry dependency다.
11 public TransferMetrics(MeterRegistry registry) {Micrometer meter를 등록하고 이름·tag로 다시 찾는 registry dependency다.
12 this.registry = Objects.requireNonNull(registry);Micrometer transfer 계측 경계 학습 코드에서 `this.registry = Objects.requireNonNull(registry)` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
13 }현재 object·array·block 또는 query 범위를 열거나 닫아 구조와 실행 순서를 유지한다.
15 public <T> T record(Supplier<T> action) {Micrometer transfer 계측 경계 학습 코드의 15번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
16 Timer.Sample sample = Timer.start(registry);동작 시작 시각을 잡아 성공·예외 공통 duration 기록의 출발점을 만든다.
17 try {정상·실패 경로와 공통 cleanup/계측 경계를 분리하는 control-flow 블록이다.
18 T result = action.get();계측으로 감싼 실제 동작을 정확히 한 번 호출한다.
19 registry.counter("fcl.transfer", "outcome", "completed").increment();성공 분기의 고정 outcome counter를 1 올린다.
20 return result;Micrometer transfer 계측 경계 학습 코드의 20번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
21 } catch (RuntimeException rejected) {Micrometer transfer 계측 경계 학습 코드의 21번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
22 registry.counter("fcl.transfer", "outcome", "business_rejected").increment();RuntimeException 분기의 고정 거절 outcome counter를 1 올린다.
23 throw rejected;선행 invariant가 깨졌을 때 evidence 발행 전에 멈추는 fail-closed guard다.
24 } finally {Micrometer transfer 계측 경계 학습 코드의 24번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
25 sample.stop(registry.timer("fcl.transfer.duration"));finally 경로에서 성공·예외 모두 duration timer를 끝낸다.
26 }현재 object·array·block 또는 query 범위를 열거나 닫아 구조와 실행 순서를 유지한다.
27 }현재 object·array·block 또는 query 범위를 열거나 닫아 구조와 실행 순서를 유지한다.
28}현재 object·array·block 또는 query 범위를 열거나 닫아 구조와 실행 순서를 유지한다.
07

STEP 07 / 13

기존 수준의 한 줄 읽기·문법 해부

쉬운 설명 다음에 문법과 실행 순서를 정밀하게 읽습니다.

한 줄로 읽기

성공·업무 거절 outcome counter와 성공/실패 공통 duration timer를 기록하는 learner-typed Micrometer wrapper다. 다만 reference project packaged production source가 아니다

문법 해부

  • `Supplier<T>`가 실제 transfer 동작을 감싼다. PDF의 설명은 BusinessException을 말하지만 이 학습 source는 더 넓은 `RuntimeException`을 거절로 센다.
  • `try/catch/finally`에서 outcome counter는 분기하고 duration timer는 공통으로 멈춘다. 다만 meter API 자체가 던지면 원래 반환값·예외를 가릴 수 있다.

실행 순서

  1. Timer.Sample을 시작한다.
  2. action을 한 번 호출한다.
  3. 성공 또는 business_rejected counter를 올린다.
  4. finally에서 duration timer를 멈춘다.

W23 조각별 정밀 해설

F02-C01 · 원문 1–10줄
문법 해부
1~10줄의 `원문 1–10줄`을 입력·grain/guard·관찰·cleanup/stable output 단계로 나눈다.
실제 값 추적
항목 전체 흐름에 연결해 `fcl.transfer`을 대조한다. 이 값이 chunk 단독 산출이라는 뜻은 아니다.
정상 예
정상 예에서는 source 순서와 owner 계약이 일치해 `fcl.transfer`을 관찰한다.
틀린 예·반례
반례에서는 선행 guard·grain·stable order·cleanup을 생략한다. 동결 경계: reference project packaged production source가 아니다.
착각 방지
`원문 1–10줄`이 항목 전체 또는 외부 운영 Green을 단독 증명한다고 읽지 않는다.
하지 않는 일
이 chunk가 책임지지 않는 범위: reference project packaged production source가 아니다.
다음 연결
다음 source chunk의 입력 또는 exact local marker·SQL oracle·사람 검토 경계로 결과를 넘긴다.
F02-C02 · 원문 11–20줄
문법 해부
11~20줄의 `원문 11–20줄`을 입력·grain/guard·관찰·cleanup/stable output 단계로 나눈다.
실제 값 추적
항목 전체 흐름에 연결해 `completed`을 대조한다. 이 값이 chunk 단독 산출이라는 뜻은 아니다.
정상 예
정상 예에서는 source 순서와 owner 계약이 일치해 `completed`을 관찰한다.
틀린 예·반례
반례에서는 선행 guard·grain·stable order·cleanup을 생략한다. 동결 경계: RuntimeException 전체를 업무 거절로 분류하면 운영 분류를 더 세분해야 한다.
착각 방지
`원문 11–20줄`이 항목 전체 또는 외부 운영 Green을 단독 증명한다고 읽지 않는다.
하지 않는 일
이 chunk가 책임지지 않는 범위: RuntimeException 전체를 업무 거절로 분류하면 운영 분류를 더 세분해야 한다.
다음 연결
다음 source chunk의 입력 또는 exact local marker·SQL oracle·사람 검토 경계로 결과를 넘긴다.
F02-C03 · 원문 21–28줄
문법 해부
21~28줄의 `원문 21–28줄`을 입력·grain/guard·관찰·cleanup/stable output 단계로 나눈다.
실제 값 추적
항목 전체 흐름에 연결해 `business_rejected`을 대조한다. 이 값이 chunk 단독 산출이라는 뜻은 아니다.
정상 예
정상 예에서는 source 순서와 owner 계약이 일치해 `business_rejected`을 관찰한다.
틀린 예·반례
반례에서는 선행 guard·grain·stable order·cleanup을 생략한다. 동결 경계: registry 구현과 export 설정은 별도다.
착각 방지
`원문 21–28줄`이 항목 전체 또는 외부 운영 Green을 단독 증명한다고 읽지 않는다.
하지 않는 일
이 chunk가 책임지지 않는 범위: registry 구현과 export 설정은 별도다.
다음 연결
다음 source chunk의 입력 또는 exact local marker·SQL oracle·사람 검토 경계로 결과를 넘긴다.
반례히토리 → 니지카 → 료 → 키타
  1. 히토리

    겉보기에는 맞지만 깨지는 예는?

  2. 니지카

    PDF 설명의 BusinessException과 source의 RuntimeException 경계를 같다고 본다

  3. 그 상태는 입력 grain·owner·관찰 중 한 칸이 비어 있어.

  4. 키타

    수정한 뒤 같은 source bytes와 evidence를 다시 대조해.

08

STEP 08 / 13

실제 값 따라가기

같은 입력값이 어느 줄을 지나 어떤 결과가 되는지 추적합니다.

순서들어온 값코드가 하는 일나온 값·상태경계
F02-T01 성공Supplier returns okcompleted +1원래 값 반환commit 자체는 모름
F02-T02 거절RuntimeExceptionbusiness_rejected +1같은 예외 재던짐모든 RuntimeException을 업무 거절로 분류
F02-T03 공통두 경로finally stopduration count +1실제 p95 backend 미실행
책임 경계히토리 → 니지카 → 료 → 키타
  1. 히토리

    이 항목의 마지막 책임선은?

  2. 니지카

    직접 역할은 `Micrometer transfer 계측 경계 학습 코드`이야.

  3. 대표 경계는 `meter 등록만으로 dashboard Green이 아니다`이야.

  4. 키타

    정본/학습용 label과 local/external owner까지 확인하면 끝이야.

09

STEP 09 / 13

Micrometer·RequestId·PowerShell·PostgreSQL 내부에서 벌어지는 일

Micrometer·JUnit·PowerShell·PostgreSQL·alert/runbook에서 실제로 일어나는 일과 증명 범위를 구분합니다.

Timer.Sample

시작 시각을 잡고 stop 때 duration을 meter에 기록한다.

분산 trace나 DB wait를 자동 설명하지 않으며 stop 실패가 원래 예외를 mask할 수 있다.
Counter

고정 outcome tag 조합의 누적 횟수를 올린다.

고객·예외 메시지를 tag로 넣지 않으며 registry 실패 처리 정책은 별도다.
Exception propagation

계측 뒤 RuntimeException을 다시 던진다.

PDF의 BusinessException 설명과 learner source의 RuntimeException catch 범위가 다르다.
10

STEP 10 / 13

흔한 착각과 틀린 예

그럴듯하지만 틀린 해석을 반례로 고칩니다.

❌ PDF 설명의 BusinessException과 source의 RuntimeException 경계를 같다고 본다

왜 틀리나 Micrometer transfer 계측 경계 학습 코드의 grain·owner·관찰·경계 중 적어도 하나를 건너뛴다.

바르게 읽기 Timer.Sample을 시작한다. 그리고 source의 실제 값과 provenance를 다시 대조한다.

반례 반례에서는 `reference project packaged production source가 아니다` 상태인데도 Green을 주장하게 된다.

❌ meter increment/stop은 절대 실패하지 않아 원래 결과를 가릴 수 없다고 본다

왜 틀리나 Micrometer transfer 계측 경계 학습 코드의 grain·owner·관찰·경계 중 적어도 하나를 건너뛴다.

바르게 읽기 action을 한 번 호출한다. 그리고 source의 실제 값과 provenance를 다시 대조한다.

반례 반례에서는 `RuntimeException 전체를 업무 거절로 분류하면 운영 분류를 더 세분해야 한다` 상태인데도 Green을 주장하게 된다.

❌ exception message를 tag value로 쓴다

왜 틀리나 Micrometer transfer 계측 경계 학습 코드의 grain·owner·관찰·경계 중 적어도 하나를 건너뛴다.

바르게 읽기 성공 또는 business_rejected counter를 올린다. 그리고 source의 실제 값과 provenance를 다시 대조한다.

반례 반례에서는 `registry 구현과 export 설정은 별도다` 상태인데도 Green을 주장하게 된다.

❌ record 호출을 transfer commit 증거라 부른다

왜 틀리나 Micrometer transfer 계측 경계 학습 코드의 grain·owner·관찰·경계 중 적어도 하나를 건너뛴다.

바르게 읽기 finally에서 duration timer를 멈춘다. 그리고 source의 실제 값과 provenance를 다시 대조한다.

반례 반례에서는 `meter 등록만으로 dashboard Green이 아니다` 상태인데도 Green을 주장하게 된다.

❌ business_rejected를 모두 5xx로 해석한다

왜 틀리나 Micrometer transfer 계측 경계 학습 코드의 grain·owner·관찰·경계 중 적어도 하나를 건너뛴다.

바르게 읽기 finally에서 duration timer를 멈춘다. 그리고 source의 실제 값과 provenance를 다시 대조한다.

반례 반례에서는 `reference project packaged production source가 아니다` 상태인데도 Green을 주장하게 된다.

11

STEP 11 / 13

이 코드가 보장하지 않는 것

이 코드가 책임지지 않는 일을 분리합니다.

직접 미보장

reference project packaged production source가 아니다

이 책임을 맡는 곳: metric/query grain
직접 미보장

RuntimeException 전체를 업무 거절로 분류하면 운영 분류를 더 세분해야 한다

이 책임을 맡는 곳: 별도 local/external 실행
직접 미보장

registry 구현과 export 설정은 별도다

이 책임을 맡는 곳: secret·개인정보·운영 정책
직접 미보장

meter 등록만으로 dashboard Green이 아니다

이 책임을 맡는 곳: infrastructure·사람 검토
12

STEP 12 / 13

직접 다시 써보기

뜻 → 조각 → 전체 코드 순서로 다시 씁니다.

1단계 · 뜻부터 복원

다음 역할을 고정값과 미보장 경계까지 말한다: 성공·업무 거절 outcome counter와 성공/실패 공통 duration timer를 기록하는 learner-typed Micrometer wrapper다.

2단계 · 코드 조각 재조립

  1. 원문 1–10줄
  2. 원문 11–20줄
  3. 원문 21–28줄

3단계 · 파일 전체 다시 쓰기

28개 물리 줄을 원본 순서로 복원하고 SHA-256 30c2a35c6083c287f461599b4565b34d5d3f0b0cba1f50bfa7df68f899aa9d37와 대조한다.

자가 점검
  • 원본 source/template bytes와 줄 번호를 바꾸지 않았는가?
  • 정본 3개와 학습용 예시 8개를 구분했는가?
  • RequestId local Gate와 DB wait local drill의 Green 범위를 분리했는가?
  • dashboard·alert·incident timeline을 NOT_RUN_EXTERNAL 또는 사람 검토로 남겼는가?
  • Q37의 JOIN grain과 Q38의 SUCCESS·반개구간 가정을 드러냈는가?
13

STEP 13 / 13

전체 원본 source

감사로 고정한 전체 source를 가감 없이 확인합니다.

학습용 예시 전체 확인하기 · 정본 답안 아님
학습용 예시 · 학습자 작성 Java · 정본 답안 아님 · 실행 결과 아님illustrative/java/TransferMetrics.javaSHA-256 30c2a35c6083c287f461599b4565b34d5d3f0b0cba1f50bfa7df68f899aa9d37
TransferMetrics.java — 성공·업무 거절 counter와 duration을 한 경계에서 기록 전체
package com.example.financialcore.observability;

import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Timer;
import java.util.Objects;
import java.util.function.Supplier;

public final class TransferMetrics {
    private final MeterRegistry registry;

    public TransferMetrics(MeterRegistry registry) {
        this.registry = Objects.requireNonNull(registry);
    }

    public <T> T record(Supplier<T> action) {
        Timer.Sample sample = Timer.start(registry);
        try {
            T result = action.get();
            registry.counter("fcl.transfer", "outcome", "completed").increment();
            return result;
        } catch (RuntimeException rejected) {
            registry.counter("fcl.transfer", "outcome", "business_rejected").increment();
            throw rejected;
        } finally {
            sample.stop(registry.timer("fcl.transfer.duration"));
        }
    }
}
03

TransferMetricsTest.java — 성공·예외 모두 timer가 멈추는 두 학습 test

illustrative/java/TransferMetricsTest.java

학습용 예시 · 학습자 작성 Java · 정본 답안 아님 · 실행 결과 아님 · 학습용 예시 · 정본 답안 아님 · W23-F03
24줄 연결24줄 번역3 chunks
01

STEP 01 / 13

오늘 이 코드에서 해결할 문제

무엇을 이해해야 하는지 질문부터 잡습니다.

오늘의 한 문장

성공과 거절 두 경로 모두 counter 1회와 timer stop 1회를 확인하는 learner-typed 단위 테스트다.

  1. `tests=2`은 어느 줄에서 생기거나 검증될까?
  2. 입력→guard→관찰→cleanup 또는 stable output 순서는 무엇인가?
  3. local 자동 owner와 external human owner는 각각 누구인가?
  4. 이 source가 직접 관찰하지 않은 Green은 무엇인가?
  5. 반례는 `이 HTML 제작 과정에서 Gradle로 실행한 결과가 아니다` 경계와 어떻게 연결되는가?
이 파일에서 끝까지 다시 쓰는 값tests=2completed=1business_rejected=1timer.count=1SimpleMeterRegistry
02

STEP 02 / 13

아주 짧게: 이 코드는 왜 필요할까?

웹소설 대신 이 코드가 필요한 이유만 두 문단으로 쉽게 봅니다.

STARRY가 metric catalog·requestId 봉투·DB wait 영수증·alert/runbook·SQL grain 표를 서로 다른 칸에 놓는다.

TransferMetricsTest.java — 성공·예외 모두 timer가 멈추는 두 학습 test ― 관측 증거 흐름으로 바꾸기

성공과 거절 두 경로 모두 counter 1회와 timer stop 1회를 확인하는 learner-typed 단위 테스트다.

핵심값 tests=2, completed=1, business_rejected=1, timer.count=1, SimpleMeterRegistry을 원본 줄로 따라가되, `이 HTML 제작 과정에서 Gradle로 실행한 결과가 아니다`까지 함께 표시해 local 관찰을 외부 운영 Green으로 부풀리지 않는다.

딱 여기까지만 비유는 grain·owner·순서를 기억하게 할 뿐 실제 Gradle/Docker/PostgreSQL 실행, dashboard·notification, 운영 SLA를 자동 증명하지 않는다.

03

STEP 03 / 13

초등학생도 이해하는 설명

생활 비유와 실제 코드의 경계를 함께 확인합니다.

원문 1–10줄

1~10줄을 한 덩어리로 읽어 1번째 움직임을 본다. 성공과 거절 두 경로 모두 counter 1회와 timer stop 1회를 확인하는 learner-typed 단위 테스트다.

코드 연결
1~10줄
비유
정상 문과 반려 문을 각각 통과시켜 도장 1개와 스톱워치 1개가 남는지 확인하는 두 장짜리 검표표
비유의 끝
이 HTML 제작 과정에서 Gradle로 실행한 결과가 아니다

원문 11–20줄

11~20줄을 한 덩어리로 읽어 2번째 움직임을 본다. 성공과 거절 두 경로 모두 counter 1회와 timer stop 1회를 확인하는 learner-typed 단위 테스트다.

코드 연결
11~20줄
비유
정상 문과 반려 문을 각각 통과시켜 도장 1개와 스톱워치 1개가 남는지 확인하는 두 장짜리 검표표
비유의 끝
PDF 학습 경로의 예시 test이지 packaged W23 selector가 아니다

원문 21–28줄

21~28줄을 한 덩어리로 읽어 3번째 움직임을 본다. 성공과 거절 두 경로 모두 counter 1회와 timer stop 1회를 확인하는 learner-typed 단위 테스트다.

코드 연결
21~28줄
비유
정상 문과 반려 문을 각각 통과시켜 도장 1개와 스톱워치 1개가 남는지 확인하는 두 장짜리 검표표
비유의 끝
tag cardinality 전체를 검증하지 않는다
문제의 첫 장면히토리 → 니지카 → 료 → 키타
  1. 히토리

    첫 고정값은 `tests=2` 맞아?

  2. 니지카

    성공과 거절 두 경로 모두 counter 1회와 timer stop 1회를 확인하는 learner-typed 단위 테스트다.

  3. 원문에서 `tests=2`이 만들어지거나 확인되는 줄을 찾자.

  4. 키타

    그리고 `이 HTML 제작 과정에서 Gradle로 실행한 결과가 아니다`도 같이 적어.

입력에서 결과까지히토리 → 니지카 → 료 → 키타
  1. 히토리

    `completed=1`은 언제 생겨?

  2. 니지카

    SimpleMeterRegistry를 새로 만든다. → TransferMetrics를 연결한다.

  3. 성공 또는 예외 action을 호출한다. → outcome과 timer count를 각각 단언한다.

  4. 키타

    관찰값과 `PDF 학습 경로의 예시 test이지 packaged W23 selector가 아니다`을 분리하면 돼.

04

STEP 04 / 13

비유 ↔ 코드 전체 연결표

감사 규칙상 연결 대상인 원본 24줄을 빠짐없이 연결합니다.

단어 몇 개만 뽑은 표가 아닙니다.학습용 예시 · 학습자 작성 Java · 정본 답안 아님 · 실행 결과 아님에서 비어 있지 않은 모든 줄을 원본 줄 번호 그대로 연결했습니다.24 / 24 연결
정확한 원본 줄STARRY 비유실제 뜻·입력·결과·한계
1줄F03-L01 package com.example.financialcore.observability; 정상 문과 반려 문을 각각 통과시켜 도장 1개와 스톱워치 1개가 남는지 확인하는 두 장짜리 검표표 성공·거절 계측 불변식 학습 test 코드의 1번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
입력
fresh SimpleMeterRegistry와 성공/예외 action
결과·효과
이 줄 뒤에는 항목 전체의 `tests=2` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
이 HTML 제작 과정에서 Gradle로 실행한 결과가 아니다
3줄F03-L03 import io.micrometer.core.instrument.simple.SimpleMeterRegistry; 정상 문과 반려 문을 각각 통과시켜 도장 1개와 스톱워치 1개가 남는지 확인하는 두 장짜리 검표표 Micrometer meter를 등록하고 이름·tag로 다시 찾는 registry dependency다.
입력
fresh SimpleMeterRegistry와 성공/예외 action
결과·효과
이 줄 뒤에는 항목 전체의 `business_rejected=1` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
tag cardinality 전체를 검증하지 않는다
4줄F03-L04 import org.junit.jupiter.api.Test; 정상 문과 반려 문을 각각 통과시켜 도장 1개와 스톱워치 1개가 남는지 확인하는 두 장짜리 검표표 성공·거절 계측 불변식 학습 test 코드의 4번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
입력
fresh SimpleMeterRegistry와 성공/예외 action
결과·효과
이 줄 뒤에는 항목 전체의 `timer.count=1` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
운영 exporter·dashboard를 검증하지 않는다
6줄F03-L06 import static org.assertj.core.api.Assertions.*; 정상 문과 반려 문을 각각 통과시켜 도장 1개와 스톱워치 1개가 남는지 확인하는 두 장짜리 검표표 성공·거절 계측 불변식 학습 test 코드의 6번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
입력
fresh SimpleMeterRegistry와 성공/예외 action
결과·효과
이 줄 뒤에는 항목 전체의 `tests=2` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
PDF 학습 경로의 예시 test이지 packaged W23 selector가 아니다
8줄F03-L08 class TransferMetricsTest { 정상 문과 반려 문을 각각 통과시켜 도장 1개와 스톱워치 1개가 남는지 확인하는 두 장짜리 검표표 성공·거절 계측 불변식 학습 test 코드의 8번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
입력
fresh SimpleMeterRegistry와 성공/예외 action
결과·효과
이 줄 뒤에는 항목 전체의 `business_rejected=1` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
운영 exporter·dashboard를 검증하지 않는다
9줄F03-L09 @Test 정상 문과 반려 문을 각각 통과시켜 도장 1개와 스톱워치 1개가 남는지 확인하는 두 장짜리 검표표 독립적인 JUnit 학습 test method임을 선언한다. 제공 코드이지 실행 결과는 아니다.
입력
fresh SimpleMeterRegistry와 성공/예외 action
결과·효과
이 줄 뒤에는 항목 전체의 `timer.count=1` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
이 HTML 제작 과정에서 Gradle로 실행한 결과가 아니다
10줄F03-L10 void success_records_fixed_outcome_and_duration() { 정상 문과 반려 문을 각각 통과시켜 도장 1개와 스톱워치 1개가 남는지 확인하는 두 장짜리 검표표 성공·거절 계측 불변식 학습 test 코드의 10번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
입력
fresh SimpleMeterRegistry와 성공/예외 action
결과·효과
이 줄 뒤에는 항목 전체의 `SimpleMeterRegistry` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
PDF 학습 경로의 예시 test이지 packaged W23 selector가 아니다
11줄F03-L11 var registry = new SimpleMeterRegistry(); 정상 문과 반려 문을 각각 통과시켜 도장 1개와 스톱워치 1개가 남는지 확인하는 두 장짜리 검표표 Micrometer meter를 등록하고 이름·tag로 다시 찾는 registry dependency다.
입력
fresh SimpleMeterRegistry와 성공/예외 action
결과·효과
이 줄 뒤에는 항목 전체의 `tests=2` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
tag cardinality 전체를 검증하지 않는다
12줄F03-L12 var metrics = new TransferMetrics(registry); 정상 문과 반려 문을 각각 통과시켜 도장 1개와 스톱워치 1개가 남는지 확인하는 두 장짜리 검표표 성공·거절 계측 불변식 학습 test 코드에서 `var metrics = new TransferMetrics(registry);` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
fresh SimpleMeterRegistry와 성공/예외 action
결과·효과
이 줄 뒤에는 항목 전체의 `completed=1` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
운영 exporter·dashboard를 검증하지 않는다
13줄F03-L13 assertThat(metrics.record(() -> "ok")).isEqualTo("ok"); 정상 문과 반려 문을 각각 통과시켜 도장 1개와 스톱워치 1개가 남는지 확인하는 두 장짜리 검표표 성공·거절 계측 불변식 학습 test 코드의 13번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
입력
fresh SimpleMeterRegistry와 성공/예외 action
결과·효과
이 줄 뒤에는 항목 전체의 `business_rejected=1` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
이 HTML 제작 과정에서 Gradle로 실행한 결과가 아니다
14줄F03-L14 assertThat(registry.get("fcl.transfer").tag("outcome", "completed").counter().count()).isEqualTo(1.0); 정상 문과 반려 문을 각각 통과시켜 도장 1개와 스톱워치 1개가 남는지 확인하는 두 장짜리 검표표 성공 분기의 고정 outcome counter를 1 올린다.
입력
fresh SimpleMeterRegistry와 성공/예외 action
결과·효과
이 줄 뒤에는 항목 전체의 `timer.count=1` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
PDF 학습 경로의 예시 test이지 packaged W23 selector가 아니다
15줄F03-L15 assertThat(registry.get("fcl.transfer.duration").timer().count()).isEqualTo(1); 정상 문과 반려 문을 각각 통과시켜 도장 1개와 스톱워치 1개가 남는지 확인하는 두 장짜리 검표표 성공·거절 계측 불변식 학습 test 코드의 15번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
입력
fresh SimpleMeterRegistry와 성공/예외 action
결과·효과
이 줄 뒤에는 항목 전체의 `SimpleMeterRegistry` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
tag cardinality 전체를 검증하지 않는다
16줄F03-L16 } 정상 문과 반려 문을 각각 통과시켜 도장 1개와 스톱워치 1개가 남는지 확인하는 두 장짜리 검표표 현재 object·array·block 또는 query 범위를 열거나 닫아 구조와 실행 순서를 유지한다.
입력
fresh SimpleMeterRegistry와 성공/예외 action
결과·효과
이 줄 뒤에는 항목 전체의 `tests=2` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
운영 exporter·dashboard를 검증하지 않는다
18줄F03-L18 @Test 정상 문과 반려 문을 각각 통과시켜 도장 1개와 스톱워치 1개가 남는지 확인하는 두 장짜리 검표표 독립적인 JUnit 학습 test method임을 선언한다. 제공 코드이지 실행 결과는 아니다.
입력
fresh SimpleMeterRegistry와 성공/예외 action
결과·효과
이 줄 뒤에는 항목 전체의 `business_rejected=1` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
PDF 학습 경로의 예시 test이지 packaged W23 selector가 아니다
19줄F03-L19 void rejection_records_fixed_outcome_and_still_stops_timer() { 정상 문과 반려 문을 각각 통과시켜 도장 1개와 스톱워치 1개가 남는지 확인하는 두 장짜리 검표표 성공·거절 계측 불변식 학습 test 코드의 19번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
입력
fresh SimpleMeterRegistry와 성공/예외 action
결과·효과
이 줄 뒤에는 항목 전체의 `timer.count=1` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
tag cardinality 전체를 검증하지 않는다
20줄F03-L20 var registry = new SimpleMeterRegistry(); 정상 문과 반려 문을 각각 통과시켜 도장 1개와 스톱워치 1개가 남는지 확인하는 두 장짜리 검표표 Micrometer meter를 등록하고 이름·tag로 다시 찾는 registry dependency다.
입력
fresh SimpleMeterRegistry와 성공/예외 action
결과·효과
이 줄 뒤에는 항목 전체의 `SimpleMeterRegistry` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
운영 exporter·dashboard를 검증하지 않는다
21줄F03-L21 var metrics = new TransferMetrics(registry); 정상 문과 반려 문을 각각 통과시켜 도장 1개와 스톱워치 1개가 남는지 확인하는 두 장짜리 검표표 성공·거절 계측 불변식 학습 test 코드에서 `var metrics = new TransferMetrics(registry);` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
fresh SimpleMeterRegistry와 성공/예외 action
결과·효과
이 줄 뒤에는 항목 전체의 `tests=2` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
이 HTML 제작 과정에서 Gradle로 실행한 결과가 아니다
22줄F03-L22 assertThatThrownBy(() -> metrics.record(() -> { 정상 문과 반려 문을 각각 통과시켜 도장 1개와 스톱워치 1개가 남는지 확인하는 두 장짜리 검표표 거절 action이 원래 예외 type을 호출자에게 다시 전달하는지 확인한다.
입력
fresh SimpleMeterRegistry와 성공/예외 action
결과·효과
이 줄 뒤에는 항목 전체의 `completed=1` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
PDF 학습 경로의 예시 test이지 packaged W23 selector가 아니다
23줄F03-L23 throw new IllegalArgumentException("rejected"); 정상 문과 반려 문을 각각 통과시켜 도장 1개와 스톱워치 1개가 남는지 확인하는 두 장짜리 검표표 선행 invariant가 깨졌을 때 evidence 발행 전에 멈추는 fail-closed guard다.
입력
fresh SimpleMeterRegistry와 성공/예외 action
결과·효과
이 줄 뒤에는 항목 전체의 `business_rejected=1` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
tag cardinality 전체를 검증하지 않는다
24줄F03-L24 })).isInstanceOf(IllegalArgumentException.class); 정상 문과 반려 문을 각각 통과시켜 도장 1개와 스톱워치 1개가 남는지 확인하는 두 장짜리 검표표 성공·거절 계측 불변식 학습 test 코드의 24번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
입력
fresh SimpleMeterRegistry와 성공/예외 action
결과·효과
이 줄 뒤에는 항목 전체의 `timer.count=1` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
운영 exporter·dashboard를 검증하지 않는다
25줄F03-L25 assertThat(registry.get("fcl.transfer").tag("outcome", "business_rejected").counter().count()).isEqualTo(1.0); 정상 문과 반려 문을 각각 통과시켜 도장 1개와 스톱워치 1개가 남는지 확인하는 두 장짜리 검표표 RuntimeException 분기의 고정 거절 outcome counter를 1 올린다.
입력
fresh SimpleMeterRegistry와 성공/예외 action
결과·효과
이 줄 뒤에는 항목 전체의 `SimpleMeterRegistry` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
이 HTML 제작 과정에서 Gradle로 실행한 결과가 아니다
26줄F03-L26 assertThat(registry.get("fcl.transfer.duration").timer().count()).isEqualTo(1); 정상 문과 반려 문을 각각 통과시켜 도장 1개와 스톱워치 1개가 남는지 확인하는 두 장짜리 검표표 성공·거절 계측 불변식 학습 test 코드의 26번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
입력
fresh SimpleMeterRegistry와 성공/예외 action
결과·효과
이 줄 뒤에는 항목 전체의 `tests=2` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
PDF 학습 경로의 예시 test이지 packaged W23 selector가 아니다
27줄F03-L27 } 정상 문과 반려 문을 각각 통과시켜 도장 1개와 스톱워치 1개가 남는지 확인하는 두 장짜리 검표표 현재 object·array·block 또는 query 범위를 열거나 닫아 구조와 실행 순서를 유지한다.
입력
fresh SimpleMeterRegistry와 성공/예외 action
결과·효과
이 줄 뒤에는 항목 전체의 `completed=1` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
tag cardinality 전체를 검증하지 않는다
28줄F03-L28 } 정상 문과 반려 문을 각각 통과시켜 도장 1개와 스톱워치 1개가 남는지 확인하는 두 장짜리 검표표 현재 object·array·block 또는 query 범위를 열거나 닫아 구조와 실행 순서를 유지한다.
입력
fresh SimpleMeterRegistry와 성공/예외 action
결과·효과
이 줄 뒤에는 항목 전체의 `business_rejected=1` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
운영 exporter·dashboard를 검증하지 않는다
Green 범위히토리 → 니지카 → 료 → 키타
  1. 히토리

    marker나 문서가 보이면 W23 전체 성공이야?

  2. 니지카

    아니. 이 source가 직접 검증한 claim만 말해야 해.

  3. 직접 연결되는 대표 값은 `SimpleMeterRegistry`이야.

  4. 키타

    `tag cardinality 전체를 검증하지 않는다`는 별도 실행·사람 증거가 필요해.

05

STEP 05 / 13

원본 코드 조각

원본을 3개 의미 조각으로 나누어 그대로 확인합니다.

파일을 한꺼번에 외우지 않고 실행 의미가 이어지는 작은 조각으로 봅니다. 아래 코드는 prompt·fixture·가정을 밝힌 학습용 예시 source이며, 제공 정본 답안이 아닙니다.

F03-C01 · 원문 1–10줄1–10줄
1–10줄 원본
package com.example.financialcore.observability;

import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
import org.junit.jupiter.api.Test;

import static org.assertj.core.api.Assertions.*;

class TransferMetricsTest {
    @Test
    void success_records_fixed_outcome_and_duration() {
F03-C02 · 원문 11–20줄11–20줄
11–20줄 원본
        var registry = new SimpleMeterRegistry();
        var metrics = new TransferMetrics(registry);
        assertThat(metrics.record(() -> "ok")).isEqualTo("ok");
        assertThat(registry.get("fcl.transfer").tag("outcome", "completed").counter().count()).isEqualTo(1.0);
        assertThat(registry.get("fcl.transfer.duration").timer().count()).isEqualTo(1);
    }

    @Test
    void rejection_records_fixed_outcome_and_still_stops_timer() {
        var registry = new SimpleMeterRegistry();
F03-C03 · 원문 21–28줄21–28줄
21–28줄 원본
        var metrics = new TransferMetrics(registry);
        assertThatThrownBy(() -> metrics.record(() -> {
            throw new IllegalArgumentException("rejected");
        })).isInstanceOf(IllegalArgumentException.class);
        assertThat(registry.get("fcl.transfer").tag("outcome", "business_rejected").counter().count()).isEqualTo(1.0);
        assertThat(registry.get("fcl.transfer.duration").timer().count()).isEqualTo(1);
    }
}
06

STEP 06 / 13

코드 한 줄씩 한국어로 번역

비어 있지 않은 24줄을 모두 한국어로 옮깁니다.

전체 번역 24 / 24

비어 있지 않은 원본 줄은 하나도 생략하지 않습니다.

원본한국어 번역
1package com.example.financialcore.observability;성공·거절 계측 불변식 학습 test 코드의 1번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
3import io.micrometer.core.instrument.simple.SimpleMeterRegistry;Micrometer meter를 등록하고 이름·tag로 다시 찾는 registry dependency다.
4import org.junit.jupiter.api.Test;성공·거절 계측 불변식 학습 test 코드의 4번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
6import static org.assertj.core.api.Assertions.*;성공·거절 계측 불변식 학습 test 코드의 6번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
8class TransferMetricsTest {성공·거절 계측 불변식 학습 test 코드의 8번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
9 @Test독립적인 JUnit 학습 test method임을 선언한다. 제공 코드이지 실행 결과는 아니다.
10 void success_records_fixed_outcome_and_duration() {성공·거절 계측 불변식 학습 test 코드의 10번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
11 var registry = new SimpleMeterRegistry();Micrometer meter를 등록하고 이름·tag로 다시 찾는 registry dependency다.
12 var metrics = new TransferMetrics(registry);성공·거절 계측 불변식 학습 test 코드에서 `var metrics = new TransferMetrics(registry);` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
13 assertThat(metrics.record(() -> "ok")).isEqualTo("ok");성공·거절 계측 불변식 학습 test 코드의 13번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
14 assertThat(registry.get("fcl.transfer").tag("outcome", "completed").counter().count()).isEqualTo(1.0);성공 분기의 고정 outcome counter를 1 올린다.
15 assertThat(registry.get("fcl.transfer.duration").timer().count()).isEqualTo(1);성공·거절 계측 불변식 학습 test 코드의 15번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
16 }현재 object·array·block 또는 query 범위를 열거나 닫아 구조와 실행 순서를 유지한다.
18 @Test독립적인 JUnit 학습 test method임을 선언한다. 제공 코드이지 실행 결과는 아니다.
19 void rejection_records_fixed_outcome_and_still_stops_timer() {성공·거절 계측 불변식 학습 test 코드의 19번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
20 var registry = new SimpleMeterRegistry();Micrometer meter를 등록하고 이름·tag로 다시 찾는 registry dependency다.
21 var metrics = new TransferMetrics(registry);성공·거절 계측 불변식 학습 test 코드에서 `var metrics = new TransferMetrics(registry);` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
22 assertThatThrownBy(() -> metrics.record(() -> {거절 action이 원래 예외 type을 호출자에게 다시 전달하는지 확인한다.
23 throw new IllegalArgumentException("rejected");선행 invariant가 깨졌을 때 evidence 발행 전에 멈추는 fail-closed guard다.
24 })).isInstanceOf(IllegalArgumentException.class);성공·거절 계측 불변식 학습 test 코드의 24번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
25 assertThat(registry.get("fcl.transfer").tag("outcome", "business_rejected").counter().count()).isEqualTo(1.0);RuntimeException 분기의 고정 거절 outcome counter를 1 올린다.
26 assertThat(registry.get("fcl.transfer.duration").timer().count()).isEqualTo(1);성공·거절 계측 불변식 학습 test 코드의 26번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
27 }현재 object·array·block 또는 query 범위를 열거나 닫아 구조와 실행 순서를 유지한다.
28}현재 object·array·block 또는 query 범위를 열거나 닫아 구조와 실행 순서를 유지한다.
07

STEP 07 / 13

기존 수준의 한 줄 읽기·문법 해부

쉬운 설명 다음에 문법과 실행 순서를 정밀하게 읽습니다.

한 줄로 읽기

성공과 거절 두 경로 모두 counter 1회와 timer stop 1회를 확인하는 learner-typed 단위 테스트다. 다만 이 HTML 제작 과정에서 Gradle로 실행한 결과가 아니다

문법 해부

  • 첫 `@Test`는 반환값·completed counter·duration count를 함께 확인한다.
  • 둘째 `@Test`는 예외 type·business_rejected counter·duration count를 함께 확인한다.

실행 순서

  1. SimpleMeterRegistry를 새로 만든다.
  2. TransferMetrics를 연결한다.
  3. 성공 또는 예외 action을 호출한다.
  4. outcome과 timer count를 각각 단언한다.

W23 조각별 정밀 해설

F03-C01 · 원문 1–10줄
문법 해부
1~10줄의 `원문 1–10줄`을 입력·grain/guard·관찰·cleanup/stable output 단계로 나눈다.
실제 값 추적
항목 전체 흐름에 연결해 `tests=2`을 대조한다. 이 값이 chunk 단독 산출이라는 뜻은 아니다.
정상 예
정상 예에서는 source 순서와 owner 계약이 일치해 `tests=2`을 관찰한다.
틀린 예·반례
반례에서는 선행 guard·grain·stable order·cleanup을 생략한다. 동결 경계: 이 HTML 제작 과정에서 Gradle로 실행한 결과가 아니다.
착각 방지
`원문 1–10줄`이 항목 전체 또는 외부 운영 Green을 단독 증명한다고 읽지 않는다.
하지 않는 일
이 chunk가 책임지지 않는 범위: 이 HTML 제작 과정에서 Gradle로 실행한 결과가 아니다.
다음 연결
다음 source chunk의 입력 또는 exact local marker·SQL oracle·사람 검토 경계로 결과를 넘긴다.
F03-C02 · 원문 11–20줄
문법 해부
11~20줄의 `원문 11–20줄`을 입력·grain/guard·관찰·cleanup/stable output 단계로 나눈다.
실제 값 추적
항목 전체 흐름에 연결해 `completed=1`을 대조한다. 이 값이 chunk 단독 산출이라는 뜻은 아니다.
정상 예
정상 예에서는 source 순서와 owner 계약이 일치해 `completed=1`을 관찰한다.
틀린 예·반례
반례에서는 선행 guard·grain·stable order·cleanup을 생략한다. 동결 경계: PDF 학습 경로의 예시 test이지 packaged W23 selector가 아니다.
착각 방지
`원문 11–20줄`이 항목 전체 또는 외부 운영 Green을 단독 증명한다고 읽지 않는다.
하지 않는 일
이 chunk가 책임지지 않는 범위: PDF 학습 경로의 예시 test이지 packaged W23 selector가 아니다.
다음 연결
다음 source chunk의 입력 또는 exact local marker·SQL oracle·사람 검토 경계로 결과를 넘긴다.
F03-C03 · 원문 21–28줄
문법 해부
21~28줄의 `원문 21–28줄`을 입력·grain/guard·관찰·cleanup/stable output 단계로 나눈다.
실제 값 추적
항목 전체 흐름에 연결해 `business_rejected=1`을 대조한다. 이 값이 chunk 단독 산출이라는 뜻은 아니다.
정상 예
정상 예에서는 source 순서와 owner 계약이 일치해 `business_rejected=1`을 관찰한다.
틀린 예·반례
반례에서는 선행 guard·grain·stable order·cleanup을 생략한다. 동결 경계: tag cardinality 전체를 검증하지 않는다.
착각 방지
`원문 21–28줄`이 항목 전체 또는 외부 운영 Green을 단독 증명한다고 읽지 않는다.
하지 않는 일
이 chunk가 책임지지 않는 범위: tag cardinality 전체를 검증하지 않는다.
다음 연결
다음 source chunk의 입력 또는 exact local marker·SQL oracle·사람 검토 경계로 결과를 넘긴다.
반례히토리 → 니지카 → 료 → 키타
  1. 히토리

    겉보기에는 맞지만 깨지는 예는?

  2. 니지카

    두 @Test가 보이면 실제 Gate가 Green이라고 한다

  3. 그 상태는 입력 grain·owner·관찰 중 한 칸이 비어 있어.

  4. 키타

    수정한 뒤 같은 source bytes와 evidence를 다시 대조해.

08

STEP 08 / 13

실제 값 따라가기

같은 입력값이 어느 줄을 지나 어떤 결과가 되는지 추적합니다.

순서들어온 값코드가 하는 일나온 값·상태경계
F03-T01 successreturns okrecordcompleted=1, duration=1실제 packaged test 실행 아님
F03-T02 rejectionIllegalArgumentExceptionrecordrejected=1, duration=1다른 RuntimeException 분류 미검증
F03-T03 isolationfresh registry각 test 독립누적 오염 없음concurrency 미검증
책임 경계히토리 → 니지카 → 료 → 키타
  1. 히토리

    이 항목의 마지막 책임선은?

  2. 니지카

    직접 역할은 `성공·거절 계측 불변식 학습 test 코드`이야.

  3. 대표 경계는 `운영 exporter·dashboard를 검증하지 않는다`이야.

  4. 키타

    정본/학습용 label과 local/external owner까지 확인하면 끝이야.

09

STEP 09 / 13

Micrometer·RequestId·PowerShell·PostgreSQL 내부에서 벌어지는 일

Micrometer·JUnit·PowerShell·PostgreSQL·alert/runbook에서 실제로 일어나는 일과 증명 범위를 구분합니다.

JUnit

각 @Test method를 독립 실행한다.

이 페이지는 test runner 결과 XML을 제공하지 않는다.
AssertJ

값·예외·meter count를 읽기 쉽게 단언한다.

정확한 metric tag cardinality 전체를 검사하지 않는다.
SimpleMeterRegistry

메모리 안에서 meter를 즉시 조회한다.

Prometheus scrape·dashboard를 대신하지 않는다.

이 파일의 @Test가 실제로 고정하는 범위

success_records_fixed_outcome_and_duration

Arrange · 준비
  • 새 SimpleMeterRegistry와 TransferMetrics를 준비한다.
  • `ok`를 반환하는 Supplier를 준비한다.
Act · 행동
  • metrics.record를 한 번 호출한다.
Assert · 확인
  • 반환값은 `ok`다.
  • outcome=completed counter와 duration timer count가 각각 1이다.
직접 보장
  • 제공된 learner test source가 의도하는 성공 분기 oracle
  • 성공 경로에서 outcome과 timer를 함께 조회하는 test shape
보장하지 않음
  • 이 HTML pipeline에서 JUnit이 실제 실행됐다는 사실
  • Prometheus scrape·dashboard p95
  • meter API failure가 원래 반환값을 mask하지 않는다는 보장

첫 실패 경계 learner 구현이 성공 counter를 올리지 않으면 completed counter lookup/count assertion에서, finally stop이 없으면 duration count assertion에서 깨진다.

rejection_records_fixed_outcome_and_still_stops_timer

Arrange · 준비
  • 새 SimpleMeterRegistry와 TransferMetrics를 준비한다.
  • IllegalArgumentException을 던지는 Supplier를 준비한다.
Act · 행동
  • metrics.record를 호출해 예외 경로를 통과시킨다.
Assert · 확인
  • IllegalArgumentException이 호출자에게 다시 전달된다.
  • outcome=business_rejected counter와 duration timer count가 각각 1이다.
직접 보장
  • 제공된 learner test source가 의도하는 RuntimeException 거절 분기 oracle
  • 예외 경로에서도 finally timer를 조회하는 test shape
보장하지 않음
  • 이 HTML pipeline에서 두 @Test가 실제 실행됐다는 사실
  • PDF 설명의 BusinessException과 source RuntimeException이 같은 taxonomy라는 주장
  • registry.counter 또는 timer.stop 실패가 원래 예외를 mask하지 않는다는 보장

첫 실패 경계 catch가 예외를 삼키면 exception assertion에서, 거절 counter나 finally stop이 없으면 뒤 meter count assertion에서 깨진다.

10

STEP 10 / 13

흔한 착각과 틀린 예

그럴듯하지만 틀린 해석을 반례로 고칩니다.

❌ 두 @Test가 보이면 실제 Gate가 Green이라고 한다

왜 틀리나 성공·거절 계측 불변식 학습 test 코드의 grain·owner·관찰·경계 중 적어도 하나를 건너뛴다.

바르게 읽기 SimpleMeterRegistry를 새로 만든다. 그리고 source의 실제 값과 provenance를 다시 대조한다.

반례 반례에서는 `이 HTML 제작 과정에서 Gradle로 실행한 결과가 아니다` 상태인데도 Green을 주장하게 된다.

❌ 예외 type만 보고 timer count를 빼먹는다

왜 틀리나 성공·거절 계측 불변식 학습 test 코드의 grain·owner·관찰·경계 중 적어도 하나를 건너뛴다.

바르게 읽기 TransferMetrics를 연결한다. 그리고 source의 실제 값과 provenance를 다시 대조한다.

반례 반례에서는 `PDF 학습 경로의 예시 test이지 packaged W23 selector가 아니다` 상태인데도 Green을 주장하게 된다.

❌ 두 test가 같은 registry를 공유한다고 본다

왜 틀리나 성공·거절 계측 불변식 학습 test 코드의 grain·owner·관찰·경계 중 적어도 하나를 건너뛴다.

바르게 읽기 성공 또는 예외 action을 호출한다. 그리고 source의 실제 값과 provenance를 다시 대조한다.

반례 반례에서는 `tag cardinality 전체를 검증하지 않는다` 상태인데도 Green을 주장하게 된다.

❌ counter 1을 실제 고객 요청 1건으로 부른다

왜 틀리나 성공·거절 계측 불변식 학습 test 코드의 grain·owner·관찰·경계 중 적어도 하나를 건너뛴다.

바르게 읽기 outcome과 timer count를 각각 단언한다. 그리고 source의 실제 값과 provenance를 다시 대조한다.

반례 반례에서는 `운영 exporter·dashboard를 검증하지 않는다` 상태인데도 Green을 주장하게 된다.

❌ SimpleMeterRegistry 결과를 외부 dashboard 증거로 부른다

왜 틀리나 성공·거절 계측 불변식 학습 test 코드의 grain·owner·관찰·경계 중 적어도 하나를 건너뛴다.

바르게 읽기 outcome과 timer count를 각각 단언한다. 그리고 source의 실제 값과 provenance를 다시 대조한다.

반례 반례에서는 `이 HTML 제작 과정에서 Gradle로 실행한 결과가 아니다` 상태인데도 Green을 주장하게 된다.

11

STEP 11 / 13

이 코드가 보장하지 않는 것

이 코드가 책임지지 않는 일을 분리합니다.

직접 미보장

이 HTML 제작 과정에서 Gradle로 실행한 결과가 아니다

이 책임을 맡는 곳: metric/query grain
직접 미보장

PDF 학습 경로의 예시 test이지 packaged W23 selector가 아니다

이 책임을 맡는 곳: 별도 local/external 실행
직접 미보장

tag cardinality 전체를 검증하지 않는다

이 책임을 맡는 곳: secret·개인정보·운영 정책
직접 미보장

운영 exporter·dashboard를 검증하지 않는다

이 책임을 맡는 곳: infrastructure·사람 검토
12

STEP 12 / 13

직접 다시 써보기

뜻 → 조각 → 전체 코드 순서로 다시 씁니다.

1단계 · 뜻부터 복원

다음 역할을 고정값과 미보장 경계까지 말한다: 성공과 거절 두 경로 모두 counter 1회와 timer stop 1회를 확인하는 learner-typed 단위 테스트다.

2단계 · 코드 조각 재조립

  1. 원문 1–10줄
  2. 원문 11–20줄
  3. 원문 21–28줄

3단계 · 파일 전체 다시 쓰기

28개 물리 줄을 원본 순서로 복원하고 SHA-256 e7199c15cc451d30de589de1f5bda26cd40c4142fcf1ae5b9d645e99c7d28227와 대조한다.

자가 점검
  • 원본 source/template bytes와 줄 번호를 바꾸지 않았는가?
  • 정본 3개와 학습용 예시 8개를 구분했는가?
  • RequestId local Gate와 DB wait local drill의 Green 범위를 분리했는가?
  • dashboard·alert·incident timeline을 NOT_RUN_EXTERNAL 또는 사람 검토로 남겼는가?
  • Q37의 JOIN grain과 Q38의 SUCCESS·반개구간 가정을 드러냈는가?
13

STEP 13 / 13

전체 원본 source

감사로 고정한 전체 source를 가감 없이 확인합니다.

학습용 예시 전체 확인하기 · 정본 답안 아님
학습용 예시 · 학습자 작성 Java · 정본 답안 아님 · 실행 결과 아님illustrative/java/TransferMetricsTest.javaSHA-256 e7199c15cc451d30de589de1f5bda26cd40c4142fcf1ae5b9d645e99c7d28227
TransferMetricsTest.java — 성공·예외 모두 timer가 멈추는 두 학습 test 전체
package com.example.financialcore.observability;

import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
import org.junit.jupiter.api.Test;

import static org.assertj.core.api.Assertions.*;

class TransferMetricsTest {
    @Test
    void success_records_fixed_outcome_and_duration() {
        var registry = new SimpleMeterRegistry();
        var metrics = new TransferMetrics(registry);
        assertThat(metrics.record(() -> "ok")).isEqualTo("ok");
        assertThat(registry.get("fcl.transfer").tag("outcome", "completed").counter().count()).isEqualTo(1.0);
        assertThat(registry.get("fcl.transfer.duration").timer().count()).isEqualTo(1);
    }

    @Test
    void rejection_records_fixed_outcome_and_still_stops_timer() {
        var registry = new SimpleMeterRegistry();
        var metrics = new TransferMetrics(registry);
        assertThatThrownBy(() -> metrics.record(() -> {
            throw new IllegalArgumentException("rejected");
        })).isInstanceOf(IllegalArgumentException.class);
        assertThat(registry.get("fcl.transfer").tag("outcome", "business_rejected").counter().count()).isEqualTo(1.0);
        assertThat(registry.get("fcl.transfer.duration").timer().count()).isEqualTo(1);
    }
}
04

incident-runbook.md — requestId에서 격리 DB wait evidence까지 이어지는 정본 절차

evidence/w23/incident-runbook.md

원문 정본 · 제공 incident runbook bytes · 정본 · W23-F04
6줄 연결6줄 번역1 chunks
01

STEP 01 / 13

오늘 이 코드에서 해결할 문제

무엇을 이해해야 하는지 질문부터 잡습니다.

오늘의 한 문장

requestId 보존, 정확한 시각·상태, disposable DB wait, gate/db-wait hash와 escalation을 묶는 제공 정본 runbook이다.

  1. `X-Request-Id`은 어느 줄에서 생기거나 검증될까?
  2. 입력→guard→관찰→cleanup 또는 stable output 순서는 무엇인가?
  3. local 자동 owner와 external human owner는 각각 누구인가?
  4. 이 source가 직접 관찰하지 않은 Green은 무엇인가?
  5. 반례는 `runbook review만으로 Green이 아니다` 경계와 어떻게 연결되는가?
이 파일에서 끝까지 다시 쓰는 값X-Request-Idsanitized accountrun-w23-db-wait.ps1gate.jsoncleanup nonzero escalation
02

STEP 02 / 13

아주 짧게: 이 코드는 왜 필요할까?

웹소설 대신 이 코드가 필요한 이유만 두 문단으로 쉽게 봅니다.

STARRY가 metric catalog·requestId 봉투·DB wait 영수증·alert/runbook·SQL grain 표를 서로 다른 칸에 놓는다.

incident-runbook.md — requestId에서 격리 DB wait evidence까지 이어지는 정본 절차 ― 관측 증거 흐름으로 바꾸기

requestId 보존, 정확한 시각·상태, disposable DB wait, gate/db-wait hash와 escalation을 묶는 제공 정본 runbook이다.

핵심값 X-Request-Id, sanitized account, run-w23-db-wait.ps1, gate.json, cleanup nonzero escalation을 원본 줄로 따라가되, `runbook review만으로 Green이 아니다`까지 함께 표시해 local 관찰을 외부 운영 Green으로 부풀리지 않는다.

딱 여기까지만 비유는 grain·owner·순서를 기억하게 할 뿐 실제 Gradle/Docker/PostgreSQL 실행, dashboard·notification, 운영 SLA를 자동 증명하지 않는다.

03

STEP 03 / 13

초등학생도 이해하는 설명

생활 비유와 실제 코드의 경계를 함께 확인합니다.

원문 1–7줄

1~7줄을 한 덩어리로 읽어 1번째 움직임을 본다. requestId 보존, 정확한 시각·상태, disposable DB wait, gate/db-wait hash와 escalation을 묶는 제공 정본 runbook이다.

코드 연결
1~7줄
비유
사고 신고 번호를 받아 발생 시각·증상·격리 실험 영수증을 한 봉투에 넣고, 위험 신호가 남으면 담당자에게 넘기는 체크리스트
비유의 끝
runbook review만으로 Green이 아니다
문제의 첫 장면히토리 → 니지카 → 료 → 키타
  1. 히토리

    첫 고정값은 `X-Request-Id` 맞아?

  2. 니지카

    requestId 보존, 정확한 시각·상태, disposable DB wait, gate/db-wait hash와 escalation을 묶는 제공 정본 runbook이다.

  3. 원문에서 `X-Request-Id`이 만들어지거나 확인되는 줄을 찾자.

  4. 키타

    그리고 `runbook review만으로 Green이 아니다`도 같이 적어.

입력에서 결과까지히토리 → 니지카 → 료 → 키타
  1. 히토리

    `sanitized account`은 언제 생겨?

  2. 니지카

    X-Request-Id와 응답을 보존한다. → 시각·상태·식별자를 sanitize해 기록한다.

  3. disposable DB wait drill을 실행한다. → 두 evidence hash와 escalation 조건을 확인한다.

  4. 키타

    관찰값과 `공유 DB를 가정해 조사하지 않는다`을 분리하면 돼.

04

STEP 04 / 13

비유 ↔ 코드 전체 연결표

감사 규칙상 연결 대상인 원본 6줄을 빠짐없이 연결합니다.

단어 몇 개만 뽑은 표가 아닙니다.원문 정본 · 제공 incident runbook bytes에서 비어 있지 않은 모든 줄을 원본 줄 번호 그대로 연결했습니다.6 / 6 연결
정확한 원본 줄STARRY 비유실제 뜻·입력·결과·한계
1줄F04-L01 # W23 incident runbook (provided fixture) 사고 신고 번호를 받아 발생 시각·증상·격리 실험 영수증을 한 봉투에 넣고, 위험 신호가 남으면 담당자에게 넘기는 체크리스트 이 source의 provenance·grain·가정·반례·실행 경계를 사람이 확인할 설명 줄이다.
입력
X-Request-Id·실패시각·HTTP 상태·sanitized account·local evidence
결과·효과
이 줄 뒤에는 항목 전체의 `X-Request-Id` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
runbook review만으로 Green이 아니다
3줄F04-L03 1. Preserve the inbound `X-Request-Id` from the application log and response. 사고 신고 번호를 받아 발생 시각·증상·격리 실험 영수증을 한 봉투에 넣고, 위험 신호가 남으면 담당자에게 넘기는 체크리스트 한 실패 요청을 response와 application log 사이에서 연결할 correlation key다.
입력
X-Request-Id·실패시각·HTTP 상태·sanitized account·local evidence
결과·효과
이 줄 뒤에는 항목 전체의 `run-w23-db-wait.ps1` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
민감 account 식별자를 원문으로 남기지 않는다
4줄F04-L04 2. Capture the exact failing request time, HTTP status, and sanitized account identifier. 사고 신고 번호를 받아 발생 시각·증상·격리 실험 영수증을 한 봉투에 넣고, 위험 신호가 남으면 담당자에게 넘기는 체크리스트 민감정보 원문 대신 최소화한 계좌 식별자를 incident evidence에 남긴다.
입력
X-Request-Id·실패시각·HTTP 상태·sanitized account·local evidence
결과·효과
이 줄 뒤에는 항목 전체의 `gate.json` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
실제 incident timeline은 별도다
5줄F04-L05 3. Run the disposable `run-w23-db-wait.ps1` drill; never inspect an assumed shared database. 사고 신고 번호를 받아 발생 시각·증상·격리 실험 영수증을 한 봉투에 넣고, 위험 신호가 남으면 담당자에게 넘기는 체크리스트 공유 DB가 아닌 disposable 환경에서 row-lock wait를 관찰하는 정본 runner를 호출한다.
입력
X-Request-Id·실패시각·HTTP 상태·sanitized account·local evidence
결과·효과
이 줄 뒤에는 항목 전체의 `cleanup nonzero escalation` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
runbook review만으로 Green이 아니다
6줄F04-L06 4. Attach `gate.json` and `db-wait.json` hashes. A runbook review alone never owns Green. 사고 신고 번호를 받아 발생 시각·증상·격리 실험 영수증을 한 봉투에 넣고, 위험 신호가 남으면 담당자에게 넘기는 체크리스트 requestId regression 결과와 runbook hash를 담는 local evidence 파일을 가리킨다.
입력
X-Request-Id·실패시각·HTTP 상태·sanitized account·local evidence
결과·효과
이 줄 뒤에는 항목 전체의 `X-Request-Id` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
공유 DB를 가정해 조사하지 않는다
7줄F04-L07 5. Escalate when the request ID is absent, the wait remains after rollback, or cleanup is nonzero. 사고 신고 번호를 받아 발생 시각·증상·격리 실험 영수증을 한 봉투에 넣고, 위험 신호가 남으면 담당자에게 넘기는 체크리스트 정본 incident 초동 대응 runbook의 7번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
입력
X-Request-Id·실패시각·HTTP 상태·sanitized account·local evidence
결과·효과
이 줄 뒤에는 항목 전체의 `sanitized account` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
민감 account 식별자를 원문으로 남기지 않는다
Green 범위히토리 → 니지카 → 료 → 키타
  1. 히토리

    marker나 문서가 보이면 W23 전체 성공이야?

  2. 니지카

    아니. 이 source가 직접 검증한 claim만 말해야 해.

  3. 직접 연결되는 대표 값은 `cleanup nonzero escalation`이야.

  4. 키타

    `민감 account 식별자를 원문으로 남기지 않는다`는 별도 실행·사람 증거가 필요해.

05

STEP 05 / 13

원본 코드 조각

원본을 1개 의미 조각으로 나누어 그대로 확인합니다.

파일을 한꺼번에 외우지 않고 실행 의미가 이어지는 작은 조각으로 봅니다. 아래 코드는 hash로 고정한 native 정본 source에서 그대로 잘랐습니다.

F04-C01 · 원문 1–7줄1–7줄
1–7줄 원본
# W23 incident runbook (provided fixture)

1. Preserve the inbound `X-Request-Id` from the application log and response.
2. Capture the exact failing request time, HTTP status, and sanitized account identifier.
3. Run the disposable `run-w23-db-wait.ps1` drill; never inspect an assumed shared database.
4. Attach `gate.json` and `db-wait.json` hashes. A runbook review alone never owns Green.
5. Escalate when the request ID is absent, the wait remains after rollback, or cleanup is nonzero.
06

STEP 06 / 13

코드 한 줄씩 한국어로 번역

비어 있지 않은 6줄을 모두 한국어로 옮깁니다.

전체 번역 6 / 6

비어 있지 않은 원본 줄은 하나도 생략하지 않습니다.

원본한국어 번역
1# W23 incident runbook (provided fixture)이 source의 provenance·grain·가정·반례·실행 경계를 사람이 확인할 설명 줄이다.
31. Preserve the inbound `X-Request-Id` from the application log and response.한 실패 요청을 response와 application log 사이에서 연결할 correlation key다.
42. Capture the exact failing request time, HTTP status, and sanitized account identifier.민감정보 원문 대신 최소화한 계좌 식별자를 incident evidence에 남긴다.
53. Run the disposable `run-w23-db-wait.ps1` drill; never inspect an assumed shared database.공유 DB가 아닌 disposable 환경에서 row-lock wait를 관찰하는 정본 runner를 호출한다.
64. Attach `gate.json` and `db-wait.json` hashes. A runbook review alone never owns Green.requestId regression 결과와 runbook hash를 담는 local evidence 파일을 가리킨다.
75. Escalate when the request ID is absent, the wait remains after rollback, or cleanup is nonzero.정본 incident 초동 대응 runbook의 7번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
07

STEP 07 / 13

기존 수준의 한 줄 읽기·문법 해부

쉬운 설명 다음에 문법과 실행 순서를 정밀하게 읽습니다.

한 줄로 읽기

requestId 보존, 정확한 시각·상태, disposable DB wait, gate/db-wait hash와 escalation을 묶는 제공 정본 runbook이다. 다만 runbook review만으로 Green이 아니다

문법 해부

  • 번호 목록은 수행 순서를 고정하고 backtick 값은 exact header·runner·evidence 이름을 가리킨다.
  • `never`와 `alone never owns Green` 문장은 공유 DB 접근과 self-declared Green을 막는 책임 경계다.

실행 순서

  1. X-Request-Id와 응답을 보존한다.
  2. 시각·상태·식별자를 sanitize해 기록한다.
  3. disposable DB wait drill을 실행한다.
  4. 두 evidence hash와 escalation 조건을 확인한다.

W23 조각별 정밀 해설

F04-C01 · 원문 1–7줄
문법 해부
1~7줄의 `원문 1–7줄`을 입력·grain/guard·관찰·cleanup/stable output 단계로 나눈다.
실제 값 추적
항목 전체 흐름에 연결해 `X-Request-Id`을 대조한다. 이 값이 chunk 단독 산출이라는 뜻은 아니다.
정상 예
정상 예에서는 source 순서와 owner 계약이 일치해 `X-Request-Id`을 관찰한다.
틀린 예·반례
반례에서는 선행 guard·grain·stable order·cleanup을 생략한다. 동결 경계: runbook review만으로 Green이 아니다.
착각 방지
`원문 1–7줄`이 항목 전체 또는 외부 운영 Green을 단독 증명한다고 읽지 않는다.
하지 않는 일
이 chunk가 책임지지 않는 범위: runbook review만으로 Green이 아니다.
다음 연결
다음 source chunk의 입력 또는 exact local marker·SQL oracle·사람 검토 경계로 결과를 넘긴다.
반례히토리 → 니지카 → 료 → 키타
  1. 히토리

    겉보기에는 맞지만 깨지는 예는?

  2. 니지카

    requestId 대신 전체 고객 정보를 log에 남긴다

  3. 그 상태는 입력 grain·owner·관찰 중 한 칸이 비어 있어.

  4. 키타

    수정한 뒤 같은 source bytes와 evidence를 다시 대조해.

08

STEP 08 / 13

실제 값 따라가기

같은 입력값이 어느 줄을 지나 어떤 결과가 되는지 추적합니다.

순서들어온 값코드가 하는 일나온 값·상태경계
F04-T01 identifyX-Request-Idlog/response 대조한 요청 연결header 부재 시 escalation
F04-T02 isolatedisposable DBrow wait drill격리 evidence공유 DB 추정 접근 금지
F04-T03 attachgate.json+db-wait.jsonhash bindreview packetrunbook review만으로 Green 아님
책임 경계히토리 → 니지카 → 료 → 키타
  1. 히토리

    이 항목의 마지막 책임선은?

  2. 니지카

    직접 역할은 `정본 incident 초동 대응 runbook`이야.

  3. 대표 경계는 `실제 incident timeline은 별도다`이야.

  4. 키타

    정본/학습용 label과 local/external owner까지 확인하면 끝이야.

09

STEP 09 / 13

Micrometer·RequestId·PowerShell·PostgreSQL 내부에서 벌어지는 일

Micrometer·JUnit·PowerShell·PostgreSQL·alert/runbook에서 실제로 일어나는 일과 증명 범위를 구분합니다.

requestId

HTTP 응답과 구조화 log를 한 사건으로 연결한다.

전 구간 trace completeness를 자동 보장하지 않는다.
disposable drill

가정한 운영 DB 대신 격리 fixture에서 wait를 만든다.

운영 장애 재현과 동일하다는 뜻은 아니다.
runbook owner

이 root incident-runbook.md가 escalation·evidence 누락 때 멈출 기준을 준다.

D6의 illustrative runbooks index와 서로 다른 파일이며 실행 evidence 생산자는 별도 runner다.
10

STEP 10 / 13

흔한 착각과 틀린 예

그럴듯하지만 틀린 해석을 반례로 고칩니다.

❌ requestId 대신 전체 고객 정보를 log에 남긴다

왜 틀리나 정본 incident 초동 대응 runbook의 grain·owner·관찰·경계 중 적어도 하나를 건너뛴다.

바르게 읽기 X-Request-Id와 응답을 보존한다. 그리고 source의 실제 값과 provenance를 다시 대조한다.

반례 반례에서는 `runbook review만으로 Green이 아니다` 상태인데도 Green을 주장하게 된다.

❌ 공유 DB를 운영 DB라고 추정하고 조회한다

왜 틀리나 정본 incident 초동 대응 runbook의 grain·owner·관찰·경계 중 적어도 하나를 건너뛴다.

바르게 읽기 시각·상태·식별자를 sanitize해 기록한다. 그리고 source의 실제 값과 provenance를 다시 대조한다.

반례 반례에서는 `공유 DB를 가정해 조사하지 않는다` 상태인데도 Green을 주장하게 된다.

❌ runbook을 읽은 것만으로 incident 해결이라 한다

왜 틀리나 정본 incident 초동 대응 runbook의 grain·owner·관찰·경계 중 적어도 하나를 건너뛴다.

바르게 읽기 disposable DB wait drill을 실행한다. 그리고 source의 실제 값과 provenance를 다시 대조한다.

반례 반례에서는 `민감 account 식별자를 원문으로 남기지 않는다` 상태인데도 Green을 주장하게 된다.

❌ gate.json hash 없이 screenshot만 붙인다

왜 틀리나 정본 incident 초동 대응 runbook의 grain·owner·관찰·경계 중 적어도 하나를 건너뛴다.

바르게 읽기 두 evidence hash와 escalation 조건을 확인한다. 그리고 source의 실제 값과 provenance를 다시 대조한다.

반례 반례에서는 `실제 incident timeline은 별도다` 상태인데도 Green을 주장하게 된다.

❌ cleanup nonzero인데 escalation을 생략한다

왜 틀리나 정본 incident 초동 대응 runbook의 grain·owner·관찰·경계 중 적어도 하나를 건너뛴다.

바르게 읽기 두 evidence hash와 escalation 조건을 확인한다. 그리고 source의 실제 값과 provenance를 다시 대조한다.

반례 반례에서는 `runbook review만으로 Green이 아니다` 상태인데도 Green을 주장하게 된다.

11

STEP 11 / 13

이 코드가 보장하지 않는 것

이 코드가 책임지지 않는 일을 분리합니다.

직접 미보장

runbook review만으로 Green이 아니다

이 책임을 맡는 곳: metric/query grain
직접 미보장

공유 DB를 가정해 조사하지 않는다

이 책임을 맡는 곳: 별도 local/external 실행
직접 미보장

민감 account 식별자를 원문으로 남기지 않는다

이 책임을 맡는 곳: secret·개인정보·운영 정책
직접 미보장

실제 incident timeline은 별도다

이 책임을 맡는 곳: infrastructure·사람 검토
12

STEP 12 / 13

직접 다시 써보기

뜻 → 조각 → 전체 코드 순서로 다시 씁니다.

1단계 · 뜻부터 복원

다음 역할을 고정값과 미보장 경계까지 말한다: requestId 보존, 정확한 시각·상태, disposable DB wait, gate/db-wait hash와 escalation을 묶는 제공 정본 runbook이다.

2단계 · 코드 조각 재조립

  1. 원문 1–7줄

3단계 · 파일 전체 다시 쓰기

7개 물리 줄을 원본 순서로 복원하고 SHA-256 a09ab2252b379c1ab1fb88ccb861f39ebf6a955a90f30d92646f941e6dd04446와 대조한다.

자가 점검
  • 원본 source/template bytes와 줄 번호를 바꾸지 않았는가?
  • 정본 3개와 학습용 예시 8개를 구분했는가?
  • RequestId local Gate와 DB wait local drill의 Green 범위를 분리했는가?
  • dashboard·alert·incident timeline을 NOT_RUN_EXTERNAL 또는 사람 검토로 남겼는가?
  • Q37의 JOIN grain과 Q38의 SUCCESS·반개구간 가정을 드러냈는가?
13

STEP 13 / 13

전체 원본 source

감사로 고정한 전체 source를 가감 없이 확인합니다.

원문 정본 전체 source 확인하기
원문 정본 · 제공 incident runbook bytesevidence/w23/incident-runbook.mdSHA-256 a09ab2252b379c1ab1fb88ccb861f39ebf6a955a90f30d92646f941e6dd04446
incident-runbook.md — requestId에서 격리 DB wait evidence까지 이어지는 정본 절차 전체
# W23 incident runbook (provided fixture)

1. Preserve the inbound `X-Request-Id` from the application log and response.
2. Capture the exact failing request time, HTTP status, and sanitized account identifier.
3. Run the disposable `run-w23-db-wait.ps1` drill; never inspect an assumed shared database.
4. Attach `gate.json` and `db-wait.json` hashes. A runbook review alone never owns Green.
5. Escalate when the request ID is absent, the wait remains after rollback, or cleanup is nonzero.
05

run-w23-gate.ps1 — RequestIdFilterTest 정확히 2개와 runbook hash를 묶는 정본 Gate

scripts/run-w23-gate.ps1

원문 정본 · 완전한 packaged PowerShell source · 정본 · W23-F05
3줄 연결3줄 번역1 chunks
01

STEP 01 / 13

오늘 이 코드에서 해결할 문제

무엇을 이해해야 하는지 질문부터 잡습니다.

오늘의 한 문장

RequestIdFilterTest 정확히 2개와 runbook hash를 검증해 request-id-regression-and-runbook 범위 gate.json을 원자 발행하는 제공 정본 Gate다.

  1. `classes=1`은 어느 줄에서 생기거나 검증될까?
  2. 입력→guard→관찰→cleanup 또는 stable output 순서는 무엇인가?
  3. local 자동 owner와 external human owner는 각각 누구인가?
  4. 이 source가 직접 관찰하지 않은 Green은 무엇인가?
  5. 반례는 `dashboard·p95·pool·외부 알림 Green을 주장하지 않는다` 경계와 어떻게 연결되는가?
이 파일에서 끝까지 다시 쓰는 값classes=1tests=2failures=0runbook_sha256W23_OBSERVABILITY_GREEN
02

STEP 02 / 13

아주 짧게: 이 코드는 왜 필요할까?

웹소설 대신 이 코드가 필요한 이유만 두 문단으로 쉽게 봅니다.

STARRY가 metric catalog·requestId 봉투·DB wait 영수증·alert/runbook·SQL grain 표를 서로 다른 칸에 놓는다.

run-w23-gate.ps1 — RequestIdFilterTest 정확히 2개와 runbook hash를 묶는 정본 Gate ― 관측 증거 흐름으로 바꾸기

RequestIdFilterTest 정확히 2개와 runbook hash를 검증해 request-id-regression-and-runbook 범위 gate.json을 원자 발행하는 제공 정본 Gate다.

핵심값 classes=1, tests=2, failures=0, runbook_sha256, W23_OBSERVABILITY_GREEN을 원본 줄로 따라가되, `dashboard·p95·pool·외부 알림 Green을 주장하지 않는다`까지 함께 표시해 local 관찰을 외부 운영 Green으로 부풀리지 않는다.

딱 여기까지만 비유는 grain·owner·순서를 기억하게 할 뿐 실제 Gradle/Docker/PostgreSQL 실행, dashboard·notification, 운영 SLA를 자동 증명하지 않는다.

03

STEP 03 / 13

초등학생도 이해하는 설명

생활 비유와 실제 코드의 경계를 함께 확인합니다.

원문 1–3줄

1~3줄을 한 덩어리로 읽어 1번째 움직임을 본다. RequestIdFilterTest 정확히 2개와 runbook hash를 검증해 request-id-regression-and-runbook 범위 gate.json을 원자 발행하는 제공 정본 Gate다.

코드 연결
1~3줄
비유
감독이 지정 선수 한 명의 시험지 두 장과 규정집 봉인 hash를 확인한 뒤에만 공식 도장을 찍는 자동 검문소
비유의 끝
dashboard·p95·pool·외부 알림 Green을 주장하지 않는다
문제의 첫 장면히토리 → 니지카 → 료 → 키타
  1. 히토리

    첫 고정값은 `classes=1` 맞아?

  2. 니지카

    RequestIdFilterTest 정확히 2개와 runbook hash를 검증해 request-id-regression-and-runbook 범위 gate.json을 원자 발행하는 제공 정본 Gate다.

  3. 원문에서 `classes=1`이 만들어지거나 확인되는 줄을 찾자.

  4. 키타

    그리고 `dashboard·p95·pool·외부 알림 Green을 주장하지 않는다`도 같이 적어.

입력에서 결과까지히토리 → 니지카 → 료 → 키타
  1. 히토리

    `tests=2`은 언제 생겨?

  2. 니지카

    project와 runbook 존재를 고정한다. → RequestIdFilterTest selector만 재실행한다.

  3. XML tests=2와 실패 0을 확인한다. → runbook hash가 든 gate.json을 원자적으로 발행한다.

  4. 키타

    관찰값과 `Gradle·JDK 실행 환경이 필요하다`을 분리하면 돼.

04

STEP 04 / 13

비유 ↔ 코드 전체 연결표

감사 규칙상 연결 대상인 원본 3줄을 빠짐없이 연결합니다.

단어 몇 개만 뽑은 표가 아닙니다.원문 정본 · 완전한 packaged PowerShell source에서 비어 있지 않은 모든 줄을 원본 줄 번호 그대로 연결했습니다.3 / 3 연결
정확한 원본 줄STARRY 비유실제 뜻·입력·결과·한계
1줄F05-L01 param([Parameter(Mandatory=$true)][string]$ProjectRoot,[Parameter(Mandatory=$true)][string]$EvidenceDir) 감독이 지정 선수 한 명의 시험지 두 장과 규정집 봉인 hash를 확인한 뒤에만 공식 도장을 찍는 자동 검문소 정본 requestId regression·runbook hash evidence producer에서 `param([Parameter(Mandatory=$true)][string]$Proje` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
project root·evidence directory·RequestIdFilterTest XML·runbook bytes
결과·효과
이 줄 뒤에는 항목 전체의 `classes=1` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
dashboard·p95·pool·외부 알림 Green을 주장하지 않는다
2줄F05-L02 $ErrorActionPreference='Stop';$root=(Resolve-Path -LiteralPath $ProjectRoot).Path;$e=[IO.Path]::GetFullPath($EvidenceDir);$class='com.example.financialcore.api.RequestIdFilterTest';$runbook=Join-Path $root 'evidence/w23/incident-runbook.md';if(!(Test-Path -LiteralPath $runbook -PathType Leaf)){throw 'W23 hashed runbook missing'};Push-Location $root 감독이 지정 선수 한 명의 시험지 두 장과 규정집 봉인 hash를 확인한 뒤에만 공식 도장을 찍는 자동 검문소 W23 Gate가 정확히 선택하는 requestId regression class 이름을 고정한다.
입력
project root·evidence directory·RequestIdFilterTest XML·runbook bytes
결과·효과
이 줄 뒤에는 항목 전체의 `tests=2` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
Gradle·JDK 실행 환경이 필요하다
3줄F05-L03 try{& .\gradlew.bat test --rerun-tasks --no-daemon --tests $class;if($LASTEXITCODE-ne 0){throw "W23 Gradle exit=$LASTEXITCODE"};$xml=Get-Item -LiteralPath 'build/test-results/test/TEST-com.example.financialcore.api.RequestIdFilterTest.xml';[xml]$x=Get-Content -Raw $xml.FullName;$s=$x.testsuite;if([string]$s.name-ne$class-or[int]$s.tests-ne 2-or[int]$s.failures-ne 0-or[int]$s.errors-ne 0-or[int]$s.skipped-ne 0){throw 'W23 exact RequestIdFilter XML mismatch'};New-Item -ItemType Directory -Force $e|Out-Null;$body=[ordered]@{classes=@($class);tests=2;failures=0;errors=0;skipped=0;claim='request-id-regression-and-runbook';runbook_sha256=(Get-FileHash -Algorithm SHA256 -LiteralPath $runbook).Hash.ToLowerInvariant();native_exit=0};$tmp=Join-Path $e 'gate.json.tmp';$body|ConvertTo-Json|Set-Content -Encoding utf8 $tmp;Move-Item -Force -LiteralPath $tmp -Destination (Join-Path $e 'gate.json');'W23_OBSERVABILITY_GREEN classes=1 tests=2 claim=request-id-regression-and-runbook native_exit=0'}finally{Pop-Location} 감독이 지정 선수 한 명의 시험지 두 장과 규정집 봉인 hash를 확인한 뒤에만 공식 도장을 찍는 자동 검문소 requestId regression 결과와 runbook hash를 담는 local evidence 파일을 가리킨다.
입력
project root·evidence directory·RequestIdFilterTest XML·runbook bytes
결과·효과
이 줄 뒤에는 항목 전체의 `failures=0` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
exact XML selector만 검증한다
Green 범위히토리 → 니지카 → 료 → 키타
  1. 히토리

    marker나 문서가 보이면 W23 전체 성공이야?

  2. 니지카

    아니. 이 source가 직접 검증한 claim만 말해야 해.

  3. 직접 연결되는 대표 값은 `W23_OBSERVABILITY_GREEN`이야.

  4. 키타

    `exact XML selector만 검증한다`는 별도 실행·사람 증거가 필요해.

05

STEP 05 / 13

원본 코드 조각

원본을 1개 의미 조각으로 나누어 그대로 확인합니다.

파일을 한꺼번에 외우지 않고 실행 의미가 이어지는 작은 조각으로 봅니다. 아래 코드는 hash로 고정한 native 정본 source에서 그대로 잘랐습니다.

F05-C01 · 원문 1–3줄1–3줄
1–3줄 원본
param([Parameter(Mandatory=$true)][string]$ProjectRoot,[Parameter(Mandatory=$true)][string]$EvidenceDir)
$ErrorActionPreference='Stop';$root=(Resolve-Path -LiteralPath $ProjectRoot).Path;$e=[IO.Path]::GetFullPath($EvidenceDir);$class='com.example.financialcore.api.RequestIdFilterTest';$runbook=Join-Path $root 'evidence/w23/incident-runbook.md';if(!(Test-Path -LiteralPath $runbook -PathType Leaf)){throw 'W23 hashed runbook missing'};Push-Location $root
try{& .\gradlew.bat test --rerun-tasks --no-daemon --tests $class;if($LASTEXITCODE-ne 0){throw "W23 Gradle exit=$LASTEXITCODE"};$xml=Get-Item -LiteralPath 'build/test-results/test/TEST-com.example.financialcore.api.RequestIdFilterTest.xml';[xml]$x=Get-Content -Raw $xml.FullName;$s=$x.testsuite;if([string]$s.name-ne$class-or[int]$s.tests-ne 2-or[int]$s.failures-ne 0-or[int]$s.errors-ne 0-or[int]$s.skipped-ne 0){throw 'W23 exact RequestIdFilter XML mismatch'};New-Item -ItemType Directory -Force $e|Out-Null;$body=[ordered]@{classes=@($class);tests=2;failures=0;errors=0;skipped=0;claim='request-id-regression-and-runbook';runbook_sha256=(Get-FileHash -Algorithm SHA256 -LiteralPath $runbook).Hash.ToLowerInvariant();native_exit=0};$tmp=Join-Path $e 'gate.json.tmp';$body|ConvertTo-Json|Set-Content -Encoding utf8 $tmp;Move-Item -Force -LiteralPath $tmp -Destination (Join-Path $e 'gate.json');'W23_OBSERVABILITY_GREEN classes=1 tests=2 claim=request-id-regression-and-runbook native_exit=0'}finally{Pop-Location}
06

STEP 06 / 13

코드 한 줄씩 한국어로 번역

비어 있지 않은 3줄을 모두 한국어로 옮깁니다.

전체 번역 3 / 3

비어 있지 않은 원본 줄은 하나도 생략하지 않습니다.

원본한국어 번역
1param([Parameter(Mandatory=$true)][string]$ProjectRoot,[Parameter(Mandatory=$true)][string]$EvidenceDir)정본 requestId regression·runbook hash evidence producer에서 `param([Parameter(Mandatory=$true)][string]$Proje` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
2$ErrorActionPreference='Stop';$root=(Resolve-Path -LiteralPath $ProjectRoot).Path;$e=[IO.Path]::GetFullPath($EvidenceDir);$class='com.example.financialcore.api.RequestIdFilterTest';$runbook=Join-Path $root 'evidence/w23/incident-runbook.md';if(!(Test-Path -LiteralPath $runbook -PathType Leaf)){throw 'W23 hashed runbook missing'};Push-Location $rootW23 Gate가 정확히 선택하는 requestId regression class 이름을 고정한다.
3try{& .\gradlew.bat test --rerun-tasks --no-daemon --tests $class;if($LASTEXITCODE-ne 0){throw "W23 Gradle exit=$LASTEXITCODE"};$xml=Get-Item -LiteralPath 'build/test-results/test/TEST-com.example.financialcore.api.RequestIdFilterTest.xml';[xml]$x=Get-Content -Raw $xml.FullName;$s=$x.testsuite;if([string]$s.name-ne$class-or[int]$s.tests-ne 2-or[int]$s.failures-ne 0-or[int]$s.errors-ne 0-or[int]$s.skipped-ne 0){throw 'W23 exact RequestIdFilter XML mismatch'};New-Item -ItemType Directory -Force $e|Out-Null;$body=[ordered]@{classes=@($class);tests=2;failures=0;errors=0;skipped=0;claim='request-id-regression-and-runbook';runbook_sha256=(Get-FileHash -Algorithm SHA256 -LiteralPath $runbook).Hash.ToLowerInvariant();native_exit=0};$tmp=Join-Path $e 'gate.json.tmp';$body|ConvertTo-Json|Set-Content -Encoding utf8 $tmp;Move-Item -Force -LiteralPath $tmp -Destination (Join-Path $e 'gate.json');'W23_OBSERVABILITY_GREEN classes=1 tests=2 claim=request-id-regression-and-runbook native_exit=0'}finally{Pop-Location}requestId regression 결과와 runbook hash를 담는 local evidence 파일을 가리킨다.
07

STEP 07 / 13

기존 수준의 한 줄 읽기·문법 해부

쉬운 설명 다음에 문법과 실행 순서를 정밀하게 읽습니다.

한 줄로 읽기

RequestIdFilterTest 정확히 2개와 runbook hash를 검증해 request-id-regression-and-runbook 범위 gate.json을 원자 발행하는 제공 정본 Gate다. 다만 dashboard·p95·pool·외부 알림 Green을 주장하지 않는다

문법 해부

  • 두 mandatory parameter는 project source와 evidence 목적지를 caller가 명시하게 한다.
  • minified 본문도 Gradle exit·exact XML counts·runbook hash·atomic move·exact marker 순서가 모두 살아 있다.

실행 순서

  1. project와 runbook 존재를 고정한다.
  2. RequestIdFilterTest selector만 재실행한다.
  3. XML tests=2와 실패 0을 확인한다.
  4. runbook hash가 든 gate.json을 원자적으로 발행한다.

W23 조각별 정밀 해설

F05-C01 · 원문 1–3줄
문법 해부
1~3줄의 `원문 1–3줄`을 입력·grain/guard·관찰·cleanup/stable output 단계로 나눈다.
실제 값 추적
항목 전체 흐름에 연결해 `classes=1`을 대조한다. 이 값이 chunk 단독 산출이라는 뜻은 아니다.
정상 예
정상 예에서는 source 순서와 owner 계약이 일치해 `classes=1`을 관찰한다.
틀린 예·반례
반례에서는 선행 guard·grain·stable order·cleanup을 생략한다. 동결 경계: dashboard·p95·pool·외부 알림 Green을 주장하지 않는다.
착각 방지
`원문 1–3줄`이 항목 전체 또는 외부 운영 Green을 단독 증명한다고 읽지 않는다.
하지 않는 일
이 chunk가 책임지지 않는 범위: dashboard·p95·pool·외부 알림 Green을 주장하지 않는다.
다음 연결
다음 source chunk의 입력 또는 exact local marker·SQL oracle·사람 검토 경계로 결과를 넘긴다.
반례히토리 → 니지카 → 료 → 키타
  1. 히토리

    겉보기에는 맞지만 깨지는 예는?

  2. 니지카

    전체 test suite가 Green이라고 확대한다

  3. 그 상태는 입력 grain·owner·관찰 중 한 칸이 비어 있어.

  4. 키타

    수정한 뒤 같은 source bytes와 evidence를 다시 대조해.

08

STEP 08 / 13

실제 값 따라가기

같은 입력값이 어느 줄을 지나 어떤 결과가 되는지 추적합니다.

순서들어온 값코드가 하는 일나온 값·상태경계
F05-T01 selectorexact classGradle --tests한 class 실행TransferMetricsTest selector 아님
F05-T02 XMLtestsuite2/0/0/0 검사regression pass외부 dashboard 미검증
F05-T03 evidencerunbook bytesSHA-256+moveW23_OBSERVABILITY_GREENrequestId+runbook 범위만
책임 경계히토리 → 니지카 → 료 → 키타
  1. 히토리

    이 항목의 마지막 책임선은?

  2. 니지카

    직접 역할은 `정본 requestId regression·runbook hash evidence producer`이야.

  3. 대표 경계는 `marker 한 줄만으로 evidence byte를 대신하지 않는다`이야.

  4. 키타

    정본/학습용 label과 local/external owner까지 확인하면 끝이야.

09

STEP 09 / 13

Micrometer·RequestId·PowerShell·PostgreSQL 내부에서 벌어지는 일

Micrometer·JUnit·PowerShell·PostgreSQL·alert/runbook에서 실제로 일어나는 일과 증명 범위를 구분합니다.

Gradle

지정 test class를 clean 재실행하고 native exit를 돌려준다.

전체 test suite 성공을 뜻하지 않는다.
JUnit XML

tests·failures·errors·skipped exact 값을 제공한다.

파일 존재만으로 최신 실행이라고 볼 수 없다.
evidence publish

temporary JSON을 final gate.json으로 교체한다.

marker만 복사하면 runbook hash binding이 없다.
10

STEP 10 / 13

흔한 착각과 틀린 예

그럴듯하지만 틀린 해석을 반례로 고칩니다.

❌ 전체 test suite가 Green이라고 확대한다

왜 틀리나 정본 requestId regression·runbook hash evidence producer의 grain·owner·관찰·경계 중 적어도 하나를 건너뛴다.

바르게 읽기 project와 runbook 존재를 고정한다. 그리고 source의 실제 값과 provenance를 다시 대조한다.

반례 반례에서는 `dashboard·p95·pool·외부 알림 Green을 주장하지 않는다` 상태인데도 Green을 주장하게 된다.

❌ tests가 2 이상이면 통과시킨다

왜 틀리나 정본 requestId regression·runbook hash evidence producer의 grain·owner·관찰·경계 중 적어도 하나를 건너뛴다.

바르게 읽기 RequestIdFilterTest selector만 재실행한다. 그리고 source의 실제 값과 provenance를 다시 대조한다.

반례 반례에서는 `Gradle·JDK 실행 환경이 필요하다` 상태인데도 Green을 주장하게 된다.

❌ runbook 파일만 있고 hash를 쓰지 않는다

왜 틀리나 정본 requestId regression·runbook hash evidence producer의 grain·owner·관찰·경계 중 적어도 하나를 건너뛴다.

바르게 읽기 XML tests=2와 실패 0을 확인한다. 그리고 source의 실제 값과 provenance를 다시 대조한다.

반례 반례에서는 `exact XML selector만 검증한다` 상태인데도 Green을 주장하게 된다.

❌ Gradle exit를 확인하지 않는다

왜 틀리나 정본 requestId regression·runbook hash evidence producer의 grain·owner·관찰·경계 중 적어도 하나를 건너뛴다.

바르게 읽기 runbook hash가 든 gate.json을 원자적으로 발행한다. 그리고 source의 실제 값과 provenance를 다시 대조한다.

반례 반례에서는 `marker 한 줄만으로 evidence byte를 대신하지 않는다` 상태인데도 Green을 주장하게 된다.

❌ W23 marker를 dashboard·alert Green으로 해석한다

왜 틀리나 정본 requestId regression·runbook hash evidence producer의 grain·owner·관찰·경계 중 적어도 하나를 건너뛴다.

바르게 읽기 runbook hash가 든 gate.json을 원자적으로 발행한다. 그리고 source의 실제 값과 provenance를 다시 대조한다.

반례 반례에서는 `dashboard·p95·pool·외부 알림 Green을 주장하지 않는다` 상태인데도 Green을 주장하게 된다.

11

STEP 11 / 13

이 코드가 보장하지 않는 것

이 코드가 책임지지 않는 일을 분리합니다.

직접 미보장

dashboard·p95·pool·외부 알림 Green을 주장하지 않는다

이 책임을 맡는 곳: metric/query grain
직접 미보장

Gradle·JDK 실행 환경이 필요하다

이 책임을 맡는 곳: 별도 local/external 실행
직접 미보장

exact XML selector만 검증한다

이 책임을 맡는 곳: secret·개인정보·운영 정책
직접 미보장

marker 한 줄만으로 evidence byte를 대신하지 않는다

이 책임을 맡는 곳: infrastructure·사람 검토
12

STEP 12 / 13

직접 다시 써보기

뜻 → 조각 → 전체 코드 순서로 다시 씁니다.

1단계 · 뜻부터 복원

다음 역할을 고정값과 미보장 경계까지 말한다: RequestIdFilterTest 정확히 2개와 runbook hash를 검증해 request-id-regression-and-runbook 범위 gate.json을 원자 발행하는 제공 정본 Gate다.

2단계 · 코드 조각 재조립

  1. 원문 1–3줄

3단계 · 파일 전체 다시 쓰기

3개 물리 줄을 원본 순서로 복원하고 SHA-256 48de77ede64ab17dfaeda7f36bf34211c9007d1df8606ab4689559846093632a와 대조한다.

자가 점검
  • 원본 source/template bytes와 줄 번호를 바꾸지 않았는가?
  • 정본 3개와 학습용 예시 8개를 구분했는가?
  • RequestId local Gate와 DB wait local drill의 Green 범위를 분리했는가?
  • dashboard·alert·incident timeline을 NOT_RUN_EXTERNAL 또는 사람 검토로 남겼는가?
  • Q37의 JOIN grain과 Q38의 SUCCESS·반개구간 가정을 드러냈는가?
13

STEP 13 / 13

전체 원본 source

감사로 고정한 전체 source를 가감 없이 확인합니다.

원문 정본 전체 source 확인하기
원문 정본 · 완전한 packaged PowerShell sourcescripts/run-w23-gate.ps1SHA-256 48de77ede64ab17dfaeda7f36bf34211c9007d1df8606ab4689559846093632a
run-w23-gate.ps1 — RequestIdFilterTest 정확히 2개와 runbook hash를 묶는 정본 Gate 전체
param([Parameter(Mandatory=$true)][string]$ProjectRoot,[Parameter(Mandatory=$true)][string]$EvidenceDir)
$ErrorActionPreference='Stop';$root=(Resolve-Path -LiteralPath $ProjectRoot).Path;$e=[IO.Path]::GetFullPath($EvidenceDir);$class='com.example.financialcore.api.RequestIdFilterTest';$runbook=Join-Path $root 'evidence/w23/incident-runbook.md';if(!(Test-Path -LiteralPath $runbook -PathType Leaf)){throw 'W23 hashed runbook missing'};Push-Location $root
try{& .\gradlew.bat test --rerun-tasks --no-daemon --tests $class;if($LASTEXITCODE-ne 0){throw "W23 Gradle exit=$LASTEXITCODE"};$xml=Get-Item -LiteralPath 'build/test-results/test/TEST-com.example.financialcore.api.RequestIdFilterTest.xml';[xml]$x=Get-Content -Raw $xml.FullName;$s=$x.testsuite;if([string]$s.name-ne$class-or[int]$s.tests-ne 2-or[int]$s.failures-ne 0-or[int]$s.errors-ne 0-or[int]$s.skipped-ne 0){throw 'W23 exact RequestIdFilter XML mismatch'};New-Item -ItemType Directory -Force $e|Out-Null;$body=[ordered]@{classes=@($class);tests=2;failures=0;errors=0;skipped=0;claim='request-id-regression-and-runbook';runbook_sha256=(Get-FileHash -Algorithm SHA256 -LiteralPath $runbook).Hash.ToLowerInvariant();native_exit=0};$tmp=Join-Path $e 'gate.json.tmp';$body|ConvertTo-Json|Set-Content -Encoding utf8 $tmp;Move-Item -Force -LiteralPath $tmp -Destination (Join-Path $e 'gate.json');'W23_OBSERVABILITY_GREEN classes=1 tests=2 claim=request-id-regression-and-runbook native_exit=0'}finally{Pop-Location}
06

W23-SQL-Q37 — 두 1:N JOIN의 N×M 증폭과 선집계 해법

illustrative/sql/W23-SQL-Q37.sql

학습용 예시 · Q37/Q38 prompt 기반 SQL · 정본 답안 아님 · 학습용 예시 · 정본 답안 아님 · W23-F06
37줄 연결37줄 번역4 chunks
01

STEP 01 / 13

오늘 이 코드에서 해결할 문제

무엇을 이해해야 하는지 질문부터 잡습니다.

오늘의 한 문장

두 1:N 자식을 생 JOIN할 때 N×M 행 폭증이 생기는 이유와 자식별 선집계 해법을 보여 주는 비정본 Q37 예시다.

  1. `1:N:N`은 어느 줄에서 생기거나 검증될까?
  2. 입력→guard→관찰→cleanup 또는 stable output 순서는 무엇인가?
  3. local 자동 owner와 external human owner는 각각 누구인가?
  4. 이 source가 직접 관찰하지 않은 Green은 무엇인가?
  5. 반례는 `workbook 제공 정답이 아니다` 경계와 어떻게 연결되는가?
이 파일에서 끝까지 다시 쓰는 값1:N:NCOUNT DISTINCTpre-aggregatetransaction grain2x3=6
02

STEP 02 / 13

아주 짧게: 이 코드는 왜 필요할까?

웹소설 대신 이 코드가 필요한 이유만 두 문단으로 쉽게 봅니다.

STARRY가 metric catalog·requestId 봉투·DB wait 영수증·alert/runbook·SQL grain 표를 서로 다른 칸에 놓는다.

W23-SQL-Q37 — 두 1:N JOIN의 N×M 증폭과 선집계 해법 ― 관측 증거 흐름으로 바꾸기

두 1:N 자식을 생 JOIN할 때 N×M 행 폭증이 생기는 이유와 자식별 선집계 해법을 보여 주는 비정본 Q37 예시다.

핵심값 1:N:N, COUNT DISTINCT, pre-aggregate, transaction grain, 2x3=6을 원본 줄로 따라가되, `workbook 제공 정답이 아니다`까지 함께 표시해 local 관찰을 외부 운영 Green으로 부풀리지 않는다.

딱 여기까지만 비유는 grain·owner·순서를 기억하게 할 뿐 실제 Gradle/Docker/PostgreSQL 실행, dashboard·notification, 운영 SLA를 자동 증명하지 않는다.

03

STEP 03 / 13

초등학생도 이해하는 설명

생활 비유와 실제 코드의 경계를 함께 확인합니다.

원문 1–10줄

1~10줄을 한 덩어리로 읽어 1번째 움직임을 본다. 두 1:N 자식을 생 JOIN할 때 N×M 행 폭증이 생기는 이유와 자식별 선집계 해법을 보여 주는 비정본 Q37 예시다.

코드 연결
1~10줄
비유
부모 한 명에게 장부 쪽지 2장과 감사 쪽지 3장을 동시에 붙이면 5장이 아니라 모든 조합 6장이 되는 좌석표
비유의 끝
workbook 제공 정답이 아니다

원문 11–20줄

11~20줄을 한 덩어리로 읽어 2번째 움직임을 본다. 두 1:N 자식을 생 JOIN할 때 N×M 행 폭증이 생기는 이유와 자식별 선집계 해법을 보여 주는 비정본 Q37 예시다.

코드 연결
11~20줄
비유
부모 한 명에게 장부 쪽지 2장과 감사 쪽지 3장을 동시에 붙이면 5장이 아니라 모든 조합 6장이 되는 좌석표
비유의 끝
COUNT DISTINCT만으로 금액 SUM 중복이 자동 해결되지는 않는다

원문 21–30줄

21~30줄을 한 덩어리로 읽어 3번째 움직임을 본다. 두 1:N 자식을 생 JOIN할 때 N×M 행 폭증이 생기는 이유와 자식별 선집계 해법을 보여 주는 비정본 Q37 예시다.

코드 연결
21~30줄
비유
부모 한 명에게 장부 쪽지 2장과 감사 쪽지 3장을 동시에 붙이면 5장이 아니라 모든 조합 6장이 되는 좌석표
비유의 끝
audit_event의 nullable tx_id를 설명해야 한다
문제의 첫 장면히토리 → 니지카 → 료 → 키타
  1. 히토리

    첫 고정값은 `1:N:N` 맞아?

  2. 니지카

    두 1:N 자식을 생 JOIN할 때 N×M 행 폭증이 생기는 이유와 자식별 선집계 해법을 보여 주는 비정본 Q37 예시다.

  3. 원문에서 `1:N:N`이 만들어지거나 확인되는 줄을 찾자.

  4. 키타

    그리고 `workbook 제공 정답이 아니다`도 같이 적어.

입력에서 결과까지히토리 → 니지카 → 료 → 키타
  1. 히토리

    `COUNT DISTINCT`은 언제 생겨?

  2. 니지카

    business_tx를 parent grain으로 선언한다. → raw JOIN의 joined_rows와 distinct child 수를 비교한다.

  3. 각 child를 tx_id별로 선집계한다. → 격리 2×3 반례에서 6행을 확인한다.

  4. 키타

    관찰값과 `COUNT DISTINCT만으로 금액 SUM 중복이 자동 해결되지는 않는다`을 분리하면 돼.

04

STEP 04 / 13

비유 ↔ 코드 전체 연결표

감사 규칙상 연결 대상인 원본 37줄을 빠짐없이 연결합니다.

단어 몇 개만 뽑은 표가 아닙니다.학습용 예시 · Q37/Q38 prompt 기반 SQL · 정본 답안 아님에서 비어 있지 않은 모든 줄을 원본 줄 번호 그대로 연결했습니다.37 / 37 연결
정확한 원본 줄STARRY 비유실제 뜻·입력·결과·한계
1줄F06-L01 -- 학습용 예시 · 정본 답안 아님 부모 한 명에게 장부 쪽지 2장과 감사 쪽지 3장을 동시에 붙이면 5장이 아니라 모든 조합 6장이 되는 좌석표 이 source의 provenance·grain·가정·반례·실행 경계를 사람이 확인할 설명 줄이다.
입력
business_tx parent와 ledger_entry/audit_event 두 1:N child
결과·효과
이 줄 뒤에는 항목 전체의 `1:N:N` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
workbook 제공 정답이 아니다
2줄F06-L02 -- 입력 grain: business_tx 1행/거래, ledger_entry 1행/원장 항목, audit_event 1행/감사 사건 부모 한 명에게 장부 쪽지 2장과 감사 쪽지 3장을 동시에 붙이면 5장이 아니라 모든 조합 6장이 되는 좌석표 이 source의 provenance·grain·가정·반례·실행 경계를 사람이 확인할 설명 줄이다.
입력
business_tx parent와 ledger_entry/audit_event 두 1:N child
결과·효과
이 줄 뒤에는 항목 전체의 `COUNT DISTINCT` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
COUNT DISTINCT만으로 금액 SUM 중복이 자동 해결되지는 않는다
3줄F06-L03 -- 출력 grain: 거래 1행. 두 1:N 자식을 동시에 생으로 JOIN하면 N×M으로 행이 늘어날 수 있다. 부모 한 명에게 장부 쪽지 2장과 감사 쪽지 3장을 동시에 붙이면 5장이 아니라 모든 조합 6장이 되는 좌석표 이 source의 provenance·grain·가정·반례·실행 경계를 사람이 확인할 설명 줄이다.
입력
business_tx parent와 ledger_entry/audit_event 두 1:N child
결과·효과
이 줄 뒤에는 항목 전체의 `pre-aggregate` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
audit_event의 nullable tx_id를 설명해야 한다
5줄F06-L05 SELECT tx.tx_id, 부모 한 명에게 장부 쪽지 2장과 감사 쪽지 3장을 동시에 붙이면 5장이 아니라 모든 조합 6장이 되는 좌석표 SQL의 입력 grain·연결·필터·집계·stable 출력 순서를 구성하는 절이다.
입력
business_tx parent와 ledger_entry/audit_event 두 1:N child
결과·효과
이 줄 뒤에는 항목 전체의 `2x3=6` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
workbook 제공 정답이 아니다
6줄F06-L06 COUNT(*) AS joined_rows, 부모 한 명에게 장부 쪽지 2장과 감사 쪽지 3장을 동시에 붙이면 5장이 아니라 모든 조합 6장이 되는 좌석표 비정본 Q37 JOIN grain 진단 SQL의 6번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
입력
business_tx parent와 ledger_entry/audit_event 두 1:N child
결과·효과
이 줄 뒤에는 항목 전체의 `1:N:N` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
COUNT DISTINCT만으로 금액 SUM 중복이 자동 해결되지는 않는다
7줄F06-L07 COUNT(DISTINCT le.entry_id) AS ledger_rows, 부모 한 명에게 장부 쪽지 2장과 감사 쪽지 3장을 동시에 붙이면 5장이 아니라 모든 조합 6장이 되는 좌석표 JOIN 증폭과 무관하게 unique ledger child 수를 따로 센다.
입력
business_tx parent와 ledger_entry/audit_event 두 1:N child
결과·효과
이 줄 뒤에는 항목 전체의 `COUNT DISTINCT` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
audit_event의 nullable tx_id를 설명해야 한다
8줄F06-L08 COUNT(DISTINCT ae.audit_id) AS audit_rows 부모 한 명에게 장부 쪽지 2장과 감사 쪽지 3장을 동시에 붙이면 5장이 아니라 모든 조합 6장이 되는 좌석표 JOIN 증폭과 무관하게 unique audit child 수를 따로 센다.
입력
business_tx parent와 ledger_entry/audit_event 두 1:N child
결과·효과
이 줄 뒤에는 항목 전체의 `pre-aggregate` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
격리 반례는 production fixture가 아니다
9줄F06-L09 FROM business_tx AS tx 부모 한 명에게 장부 쪽지 2장과 감사 쪽지 3장을 동시에 붙이면 5장이 아니라 모든 조합 6장이 되는 좌석표 SQL의 입력 grain·연결·필터·집계·stable 출력 순서를 구성하는 절이다.
입력
business_tx parent와 ledger_entry/audit_event 두 1:N child
결과·효과
이 줄 뒤에는 항목 전체의 `transaction grain` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
workbook 제공 정답이 아니다
10줄F06-L10 JOIN ledger_entry AS le ON le.tx_id = tx.tx_id 부모 한 명에게 장부 쪽지 2장과 감사 쪽지 3장을 동시에 붙이면 5장이 아니라 모든 조합 6장이 되는 좌석표 parent transaction에 첫 1:N ledger child를 연결한다.
입력
business_tx parent와 ledger_entry/audit_event 두 1:N child
결과·효과
이 줄 뒤에는 항목 전체의 `2x3=6` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
COUNT DISTINCT만으로 금액 SUM 중복이 자동 해결되지는 않는다
11줄F06-L11 JOIN audit_event AS ae ON ae.tx_id = tx.tx_id 부모 한 명에게 장부 쪽지 2장과 감사 쪽지 3장을 동시에 붙이면 5장이 아니라 모든 조합 6장이 되는 좌석표 같은 parent에 둘째 1:N audit child를 raw 연결해 N×M 가능성을 만든다.
입력
business_tx parent와 ledger_entry/audit_event 두 1:N child
결과·효과
이 줄 뒤에는 항목 전체의 `1:N:N` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
audit_event의 nullable tx_id를 설명해야 한다
12줄F06-L12 GROUP BY tx.tx_id 부모 한 명에게 장부 쪽지 2장과 감사 쪽지 3장을 동시에 붙이면 5장이 아니라 모든 조합 6장이 되는 좌석표 SQL의 입력 grain·연결·필터·집계·stable 출력 순서를 구성하는 절이다.
입력
business_tx parent와 ledger_entry/audit_event 두 1:N child
결과·효과
이 줄 뒤에는 항목 전체의 `COUNT DISTINCT` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
격리 반례는 production fixture가 아니다
13줄F06-L13 ORDER BY tx.tx_id; 부모 한 명에게 장부 쪽지 2장과 감사 쪽지 3장을 동시에 붙이면 5장이 아니라 모든 조합 6장이 되는 좌석표 SQL의 입력 grain·연결·필터·집계·stable 출력 순서를 구성하는 절이다.
입력
business_tx parent와 ledger_entry/audit_event 두 1:N child
결과·효과
이 줄 뒤에는 항목 전체의 `pre-aggregate` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
workbook 제공 정답이 아니다
15줄F06-L15 -- 안전한 집계 예시: 각 1:N 자식을 거래 grain으로 먼저 줄인 뒤 JOIN한다. 부모 한 명에게 장부 쪽지 2장과 감사 쪽지 3장을 동시에 붙이면 5장이 아니라 모든 조합 6장이 되는 좌석표 이 source의 provenance·grain·가정·반례·실행 경계를 사람이 확인할 설명 줄이다.
입력
business_tx parent와 ledger_entry/audit_event 두 1:N child
결과·효과
이 줄 뒤에는 항목 전체의 `2x3=6` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
audit_event의 nullable tx_id를 설명해야 한다
16줄F06-L16 WITH ledger_counts AS ( 부모 한 명에게 장부 쪽지 2장과 감사 쪽지 3장을 동시에 붙이면 5장이 아니라 모든 조합 6장이 되는 좌석표 ledger child를 tx_id 한 행으로 먼저 줄이는 선집계 CTE다.
입력
business_tx parent와 ledger_entry/audit_event 두 1:N child
결과·효과
이 줄 뒤에는 항목 전체의 `1:N:N` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
격리 반례는 production fixture가 아니다
17줄F06-L17 SELECT tx_id, COUNT(*) AS ledger_rows 부모 한 명에게 장부 쪽지 2장과 감사 쪽지 3장을 동시에 붙이면 5장이 아니라 모든 조합 6장이 되는 좌석표 SQL의 입력 grain·연결·필터·집계·stable 출력 순서를 구성하는 절이다.
입력
business_tx parent와 ledger_entry/audit_event 두 1:N child
결과·효과
이 줄 뒤에는 항목 전체의 `COUNT DISTINCT` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
workbook 제공 정답이 아니다
18줄F06-L18 FROM ledger_entry 부모 한 명에게 장부 쪽지 2장과 감사 쪽지 3장을 동시에 붙이면 5장이 아니라 모든 조합 6장이 되는 좌석표 SQL의 입력 grain·연결·필터·집계·stable 출력 순서를 구성하는 절이다.
입력
business_tx parent와 ledger_entry/audit_event 두 1:N child
결과·효과
이 줄 뒤에는 항목 전체의 `pre-aggregate` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
COUNT DISTINCT만으로 금액 SUM 중복이 자동 해결되지는 않는다
19줄F06-L19 GROUP BY tx_id 부모 한 명에게 장부 쪽지 2장과 감사 쪽지 3장을 동시에 붙이면 5장이 아니라 모든 조합 6장이 되는 좌석표 SQL의 입력 grain·연결·필터·집계·stable 출력 순서를 구성하는 절이다.
입력
business_tx parent와 ledger_entry/audit_event 두 1:N child
결과·효과
이 줄 뒤에는 항목 전체의 `transaction grain` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
audit_event의 nullable tx_id를 설명해야 한다
20줄F06-L20 ), 부모 한 명에게 장부 쪽지 2장과 감사 쪽지 3장을 동시에 붙이면 5장이 아니라 모든 조합 6장이 되는 좌석표 비정본 Q37 JOIN grain 진단 SQL의 20번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
입력
business_tx parent와 ledger_entry/audit_event 두 1:N child
결과·효과
이 줄 뒤에는 항목 전체의 `2x3=6` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
격리 반례는 production fixture가 아니다
21줄F06-L21 audit_counts AS ( 부모 한 명에게 장부 쪽지 2장과 감사 쪽지 3장을 동시에 붙이면 5장이 아니라 모든 조합 6장이 되는 좌석표 audit child를 tx_id 한 행으로 먼저 줄이는 선집계 CTE다.
입력
business_tx parent와 ledger_entry/audit_event 두 1:N child
결과·효과
이 줄 뒤에는 항목 전체의 `1:N:N` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
workbook 제공 정답이 아니다
22줄F06-L22 SELECT tx_id, COUNT(*) AS audit_rows 부모 한 명에게 장부 쪽지 2장과 감사 쪽지 3장을 동시에 붙이면 5장이 아니라 모든 조합 6장이 되는 좌석표 SQL의 입력 grain·연결·필터·집계·stable 출력 순서를 구성하는 절이다.
입력
business_tx parent와 ledger_entry/audit_event 두 1:N child
결과·효과
이 줄 뒤에는 항목 전체의 `COUNT DISTINCT` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
COUNT DISTINCT만으로 금액 SUM 중복이 자동 해결되지는 않는다
23줄F06-L23 FROM audit_event 부모 한 명에게 장부 쪽지 2장과 감사 쪽지 3장을 동시에 붙이면 5장이 아니라 모든 조합 6장이 되는 좌석표 SQL의 입력 grain·연결·필터·집계·stable 출력 순서를 구성하는 절이다.
입력
business_tx parent와 ledger_entry/audit_event 두 1:N child
결과·효과
이 줄 뒤에는 항목 전체의 `pre-aggregate` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
audit_event의 nullable tx_id를 설명해야 한다
24줄F06-L24 WHERE tx_id IS NOT NULL 부모 한 명에게 장부 쪽지 2장과 감사 쪽지 3장을 동시에 붙이면 5장이 아니라 모든 조합 6장이 되는 좌석표 SQL의 입력 grain·연결·필터·집계·stable 출력 순서를 구성하는 절이다.
입력
business_tx parent와 ledger_entry/audit_event 두 1:N child
결과·효과
이 줄 뒤에는 항목 전체의 `transaction grain` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
격리 반례는 production fixture가 아니다
25줄F06-L25 GROUP BY tx_id 부모 한 명에게 장부 쪽지 2장과 감사 쪽지 3장을 동시에 붙이면 5장이 아니라 모든 조합 6장이 되는 좌석표 SQL의 입력 grain·연결·필터·집계·stable 출력 순서를 구성하는 절이다.
입력
business_tx parent와 ledger_entry/audit_event 두 1:N child
결과·효과
이 줄 뒤에는 항목 전체의 `2x3=6` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
workbook 제공 정답이 아니다
26줄F06-L26 ) 부모 한 명에게 장부 쪽지 2장과 감사 쪽지 3장을 동시에 붙이면 5장이 아니라 모든 조합 6장이 되는 좌석표 현재 object·array·block 또는 query 범위를 열거나 닫아 구조와 실행 순서를 유지한다.
입력
business_tx parent와 ledger_entry/audit_event 두 1:N child
결과·효과
이 줄 뒤에는 항목 전체의 `1:N:N` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
COUNT DISTINCT만으로 금액 SUM 중복이 자동 해결되지는 않는다
27줄F06-L27 SELECT tx.tx_id, 부모 한 명에게 장부 쪽지 2장과 감사 쪽지 3장을 동시에 붙이면 5장이 아니라 모든 조합 6장이 되는 좌석표 SQL의 입력 grain·연결·필터·집계·stable 출력 순서를 구성하는 절이다.
입력
business_tx parent와 ledger_entry/audit_event 두 1:N child
결과·효과
이 줄 뒤에는 항목 전체의 `COUNT DISTINCT` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
audit_event의 nullable tx_id를 설명해야 한다
28줄F06-L28 COALESCE(le.ledger_rows, 0) AS ledger_rows, 부모 한 명에게 장부 쪽지 2장과 감사 쪽지 3장을 동시에 붙이면 5장이 아니라 모든 조합 6장이 되는 좌석표 비정본 Q37 JOIN grain 진단 SQL의 28번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
입력
business_tx parent와 ledger_entry/audit_event 두 1:N child
결과·효과
이 줄 뒤에는 항목 전체의 `pre-aggregate` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
격리 반례는 production fixture가 아니다
29줄F06-L29 COALESCE(ae.audit_rows, 0) AS audit_rows 부모 한 명에게 장부 쪽지 2장과 감사 쪽지 3장을 동시에 붙이면 5장이 아니라 모든 조합 6장이 되는 좌석표 비정본 Q37 JOIN grain 진단 SQL의 29번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
입력
business_tx parent와 ledger_entry/audit_event 두 1:N child
결과·효과
이 줄 뒤에는 항목 전체의 `transaction grain` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
workbook 제공 정답이 아니다
30줄F06-L30 FROM business_tx AS tx 부모 한 명에게 장부 쪽지 2장과 감사 쪽지 3장을 동시에 붙이면 5장이 아니라 모든 조합 6장이 되는 좌석표 SQL의 입력 grain·연결·필터·집계·stable 출력 순서를 구성하는 절이다.
입력
business_tx parent와 ledger_entry/audit_event 두 1:N child
결과·효과
이 줄 뒤에는 항목 전체의 `2x3=6` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
COUNT DISTINCT만으로 금액 SUM 중복이 자동 해결되지는 않는다
31줄F06-L31 LEFT JOIN ledger_counts AS le ON le.tx_id = tx.tx_id 부모 한 명에게 장부 쪽지 2장과 감사 쪽지 3장을 동시에 붙이면 5장이 아니라 모든 조합 6장이 되는 좌석표 ledger child를 tx_id 한 행으로 먼저 줄이는 선집계 CTE다.
입력
business_tx parent와 ledger_entry/audit_event 두 1:N child
결과·효과
이 줄 뒤에는 항목 전체의 `1:N:N` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
audit_event의 nullable tx_id를 설명해야 한다
32줄F06-L32 LEFT JOIN audit_counts AS ae ON ae.tx_id = tx.tx_id 부모 한 명에게 장부 쪽지 2장과 감사 쪽지 3장을 동시에 붙이면 5장이 아니라 모든 조합 6장이 되는 좌석표 audit child를 tx_id 한 행으로 먼저 줄이는 선집계 CTE다.
입력
business_tx parent와 ledger_entry/audit_event 두 1:N child
결과·효과
이 줄 뒤에는 항목 전체의 `COUNT DISTINCT` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
격리 반례는 production fixture가 아니다
33줄F06-L33 ORDER BY tx.tx_id; 부모 한 명에게 장부 쪽지 2장과 감사 쪽지 3장을 동시에 붙이면 5장이 아니라 모든 조합 6장이 되는 좌석표 SQL의 입력 grain·연결·필터·집계·stable 출력 순서를 구성하는 절이다.
입력
business_tx parent와 ledger_entry/audit_event 두 1:N child
결과·효과
이 줄 뒤에는 항목 전체의 `pre-aggregate` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
workbook 제공 정답이 아니다
35줄F06-L35 -- 격리 반례: parent 1행 × child_a 2행 × child_b 3행 = JOIN 결과 6행. 부모 한 명에게 장부 쪽지 2장과 감사 쪽지 3장을 동시에 붙이면 5장이 아니라 모든 조합 6장이 되는 좌석표 이 source의 provenance·grain·가정·반례·실행 경계를 사람이 확인할 설명 줄이다.
입력
business_tx parent와 ledger_entry/audit_event 두 1:N child
결과·효과
이 줄 뒤에는 항목 전체의 `2x3=6` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
audit_event의 nullable tx_id를 설명해야 한다
36줄F06-L36 WITH child_a(id) AS (VALUES (1), (2)), 부모 한 명에게 장부 쪽지 2장과 감사 쪽지 3장을 동시에 붙이면 5장이 아니라 모든 조합 6장이 되는 좌석표 SQL의 입력 grain·연결·필터·집계·stable 출력 순서를 구성하는 절이다.
입력
business_tx parent와 ledger_entry/audit_event 두 1:N child
결과·효과
이 줄 뒤에는 항목 전체의 `1:N:N` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
격리 반례는 production fixture가 아니다
37줄F06-L37 child_b(id) AS (VALUES (10), (20), (30)) 부모 한 명에게 장부 쪽지 2장과 감사 쪽지 3장을 동시에 붙이면 5장이 아니라 모든 조합 6장이 되는 좌석표 비정본 Q37 JOIN grain 진단 SQL의 37번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
입력
business_tx parent와 ledger_entry/audit_event 두 1:N child
결과·효과
이 줄 뒤에는 항목 전체의 `COUNT DISTINCT` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
workbook 제공 정답이 아니다
38줄F06-L38 SELECT COUNT(*) AS multiplied_rows 부모 한 명에게 장부 쪽지 2장과 감사 쪽지 3장을 동시에 붙이면 5장이 아니라 모든 조합 6장이 되는 좌석표 SQL의 입력 grain·연결·필터·집계·stable 출력 순서를 구성하는 절이다.
입력
business_tx parent와 ledger_entry/audit_event 두 1:N child
결과·효과
이 줄 뒤에는 항목 전체의 `pre-aggregate` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
COUNT DISTINCT만으로 금액 SUM 중복이 자동 해결되지는 않는다
39줄F06-L39 FROM child_a 부모 한 명에게 장부 쪽지 2장과 감사 쪽지 3장을 동시에 붙이면 5장이 아니라 모든 조합 6장이 되는 좌석표 SQL의 입력 grain·연결·필터·집계·stable 출력 순서를 구성하는 절이다.
입력
business_tx parent와 ledger_entry/audit_event 두 1:N child
결과·효과
이 줄 뒤에는 항목 전체의 `transaction grain` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
audit_event의 nullable tx_id를 설명해야 한다
40줄F06-L40 CROSS JOIN child_b; 부모 한 명에게 장부 쪽지 2장과 감사 쪽지 3장을 동시에 붙이면 5장이 아니라 모든 조합 6장이 되는 좌석표 2행과 3행의 모든 조합 6행을 만드는 격리 반례다.
입력
business_tx parent와 ledger_entry/audit_event 두 1:N child
결과·효과
이 줄 뒤에는 항목 전체의 `2x3=6` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
격리 반례는 production fixture가 아니다
Green 범위히토리 → 니지카 → 료 → 키타
  1. 히토리

    marker나 문서가 보이면 W23 전체 성공이야?

  2. 니지카

    아니. 이 source가 직접 검증한 claim만 말해야 해.

  3. 직접 연결되는 대표 값은 `2x3=6`이야.

  4. 키타

    `audit_event의 nullable tx_id를 설명해야 한다`는 별도 실행·사람 증거가 필요해.

05

STEP 05 / 13

원본 코드 조각

원본을 4개 의미 조각으로 나누어 그대로 확인합니다.

파일을 한꺼번에 외우지 않고 실행 의미가 이어지는 작은 조각으로 봅니다. 아래 코드는 prompt·fixture·가정을 밝힌 학습용 예시 source이며, 제공 정본 답안이 아닙니다.

F06-C01 · 원문 1–10줄1–10줄
1–10줄 원본
-- 학습용 예시 · 정본 답안 아님
-- 입력 grain: business_tx 1행/거래, ledger_entry 1행/원장 항목, audit_event 1행/감사 사건
-- 출력 grain: 거래 1행. 두 1:N 자식을 동시에 생으로 JOIN하면 N×M으로 행이 늘어날 수 있다.

SELECT tx.tx_id,
       COUNT(*) AS joined_rows,
       COUNT(DISTINCT le.entry_id) AS ledger_rows,
       COUNT(DISTINCT ae.audit_id) AS audit_rows
FROM business_tx AS tx
JOIN ledger_entry AS le ON le.tx_id = tx.tx_id
F06-C02 · 원문 11–20줄11–20줄
11–20줄 원본
JOIN audit_event AS ae ON ae.tx_id = tx.tx_id
GROUP BY tx.tx_id
ORDER BY tx.tx_id;

-- 안전한 집계 예시: 각 1:N 자식을 거래 grain으로 먼저 줄인 뒤 JOIN한다.
WITH ledger_counts AS (
    SELECT tx_id, COUNT(*) AS ledger_rows
    FROM ledger_entry
    GROUP BY tx_id
),
F06-C03 · 원문 21–30줄21–30줄
21–30줄 원본
audit_counts AS (
    SELECT tx_id, COUNT(*) AS audit_rows
    FROM audit_event
    WHERE tx_id IS NOT NULL
    GROUP BY tx_id
)
SELECT tx.tx_id,
       COALESCE(le.ledger_rows, 0) AS ledger_rows,
       COALESCE(ae.audit_rows, 0) AS audit_rows
FROM business_tx AS tx
F06-C04 · 원문 31–40줄31–40줄
31–40줄 원본
LEFT JOIN ledger_counts AS le ON le.tx_id = tx.tx_id
LEFT JOIN audit_counts AS ae ON ae.tx_id = tx.tx_id
ORDER BY tx.tx_id;

-- 격리 반례: parent 1행 × child_a 2행 × child_b 3행 = JOIN 결과 6행.
WITH child_a(id) AS (VALUES (1), (2)),
child_b(id) AS (VALUES (10), (20), (30))
SELECT COUNT(*) AS multiplied_rows
FROM child_a
CROSS JOIN child_b;
06

STEP 06 / 13

코드 한 줄씩 한국어로 번역

비어 있지 않은 37줄을 모두 한국어로 옮깁니다.

전체 번역 37 / 37

비어 있지 않은 원본 줄은 하나도 생략하지 않습니다.

원본한국어 번역
1-- 학습용 예시 · 정본 답안 아님이 source의 provenance·grain·가정·반례·실행 경계를 사람이 확인할 설명 줄이다.
2-- 입력 grain: business_tx 1행/거래, ledger_entry 1행/원장 항목, audit_event 1행/감사 사건이 source의 provenance·grain·가정·반례·실행 경계를 사람이 확인할 설명 줄이다.
3-- 출력 grain: 거래 1행. 두 1:N 자식을 동시에 생으로 JOIN하면 N×M으로 행이 늘어날 수 있다.이 source의 provenance·grain·가정·반례·실행 경계를 사람이 확인할 설명 줄이다.
5SELECT tx.tx_id,SQL의 입력 grain·연결·필터·집계·stable 출력 순서를 구성하는 절이다.
6 COUNT(*) AS joined_rows,비정본 Q37 JOIN grain 진단 SQL의 6번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
7 COUNT(DISTINCT le.entry_id) AS ledger_rows,JOIN 증폭과 무관하게 unique ledger child 수를 따로 센다.
8 COUNT(DISTINCT ae.audit_id) AS audit_rowsJOIN 증폭과 무관하게 unique audit child 수를 따로 센다.
9FROM business_tx AS txSQL의 입력 grain·연결·필터·집계·stable 출력 순서를 구성하는 절이다.
10JOIN ledger_entry AS le ON le.tx_id = tx.tx_idparent transaction에 첫 1:N ledger child를 연결한다.
11JOIN audit_event AS ae ON ae.tx_id = tx.tx_id같은 parent에 둘째 1:N audit child를 raw 연결해 N×M 가능성을 만든다.
12GROUP BY tx.tx_idSQL의 입력 grain·연결·필터·집계·stable 출력 순서를 구성하는 절이다.
13ORDER BY tx.tx_id;SQL의 입력 grain·연결·필터·집계·stable 출력 순서를 구성하는 절이다.
15-- 안전한 집계 예시: 각 1:N 자식을 거래 grain으로 먼저 줄인 뒤 JOIN한다.이 source의 provenance·grain·가정·반례·실행 경계를 사람이 확인할 설명 줄이다.
16WITH ledger_counts AS (ledger child를 tx_id 한 행으로 먼저 줄이는 선집계 CTE다.
17 SELECT tx_id, COUNT(*) AS ledger_rowsSQL의 입력 grain·연결·필터·집계·stable 출력 순서를 구성하는 절이다.
18 FROM ledger_entrySQL의 입력 grain·연결·필터·집계·stable 출력 순서를 구성하는 절이다.
19 GROUP BY tx_idSQL의 입력 grain·연결·필터·집계·stable 출력 순서를 구성하는 절이다.
20),비정본 Q37 JOIN grain 진단 SQL의 20번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
21audit_counts AS (audit child를 tx_id 한 행으로 먼저 줄이는 선집계 CTE다.
22 SELECT tx_id, COUNT(*) AS audit_rowsSQL의 입력 grain·연결·필터·집계·stable 출력 순서를 구성하는 절이다.
23 FROM audit_eventSQL의 입력 grain·연결·필터·집계·stable 출력 순서를 구성하는 절이다.
24 WHERE tx_id IS NOT NULLSQL의 입력 grain·연결·필터·집계·stable 출력 순서를 구성하는 절이다.
25 GROUP BY tx_idSQL의 입력 grain·연결·필터·집계·stable 출력 순서를 구성하는 절이다.
26)현재 object·array·block 또는 query 범위를 열거나 닫아 구조와 실행 순서를 유지한다.
27SELECT tx.tx_id,SQL의 입력 grain·연결·필터·집계·stable 출력 순서를 구성하는 절이다.
28 COALESCE(le.ledger_rows, 0) AS ledger_rows,비정본 Q37 JOIN grain 진단 SQL의 28번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
29 COALESCE(ae.audit_rows, 0) AS audit_rows비정본 Q37 JOIN grain 진단 SQL의 29번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
30FROM business_tx AS txSQL의 입력 grain·연결·필터·집계·stable 출력 순서를 구성하는 절이다.
31LEFT JOIN ledger_counts AS le ON le.tx_id = tx.tx_idledger child를 tx_id 한 행으로 먼저 줄이는 선집계 CTE다.
32LEFT JOIN audit_counts AS ae ON ae.tx_id = tx.tx_idaudit child를 tx_id 한 행으로 먼저 줄이는 선집계 CTE다.
33ORDER BY tx.tx_id;SQL의 입력 grain·연결·필터·집계·stable 출력 순서를 구성하는 절이다.
35-- 격리 반례: parent 1행 × child_a 2행 × child_b 3행 = JOIN 결과 6행.이 source의 provenance·grain·가정·반례·실행 경계를 사람이 확인할 설명 줄이다.
36WITH child_a(id) AS (VALUES (1), (2)),SQL의 입력 grain·연결·필터·집계·stable 출력 순서를 구성하는 절이다.
37child_b(id) AS (VALUES (10), (20), (30))비정본 Q37 JOIN grain 진단 SQL의 37번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
38SELECT COUNT(*) AS multiplied_rowsSQL의 입력 grain·연결·필터·집계·stable 출력 순서를 구성하는 절이다.
39FROM child_aSQL의 입력 grain·연결·필터·집계·stable 출력 순서를 구성하는 절이다.
40CROSS JOIN child_b;2행과 3행의 모든 조합 6행을 만드는 격리 반례다.
07

STEP 07 / 13

기존 수준의 한 줄 읽기·문법 해부

쉬운 설명 다음에 문법과 실행 순서를 정밀하게 읽습니다.

한 줄로 읽기

두 1:N 자식을 생 JOIN할 때 N×M 행 폭증이 생기는 이유와 자식별 선집계 해법을 보여 주는 비정본 Q37 예시다. 다만 workbook 제공 정답이 아니다

문법 해부

  • 두 1:N 자식을 raw JOIN하면 같은 parent 안에서 ledger N × audit M 행이 만들어진다.
  • 안전한 CTE는 각 child를 `tx_id` 한 행으로 먼저 집계한 뒤 parent에 LEFT JOIN한다.

실행 순서

  1. business_tx를 parent grain으로 선언한다.
  2. raw JOIN의 joined_rows와 distinct child 수를 비교한다.
  3. 각 child를 tx_id별로 선집계한다.
  4. 격리 2×3 반례에서 6행을 확인한다.

W23 조각별 정밀 해설

F06-C01 · 원문 1–10줄
문법 해부
1~10줄의 `원문 1–10줄`을 입력·grain/guard·관찰·cleanup/stable output 단계로 나눈다.
실제 값 추적
항목 전체 흐름에 연결해 `1:N:N`을 대조한다. 이 값이 chunk 단독 산출이라는 뜻은 아니다.
정상 예
정상 예에서는 source 순서와 owner 계약이 일치해 `1:N:N`을 관찰한다.
틀린 예·반례
반례에서는 선행 guard·grain·stable order·cleanup을 생략한다. 동결 경계: workbook 제공 정답이 아니다.
착각 방지
`원문 1–10줄`이 항목 전체 또는 외부 운영 Green을 단독 증명한다고 읽지 않는다.
하지 않는 일
이 chunk가 책임지지 않는 범위: workbook 제공 정답이 아니다.
다음 연결
다음 source chunk의 입력 또는 exact local marker·SQL oracle·사람 검토 경계로 결과를 넘긴다.
F06-C02 · 원문 11–20줄
문법 해부
11~20줄의 `원문 11–20줄`을 입력·grain/guard·관찰·cleanup/stable output 단계로 나눈다.
실제 값 추적
항목 전체 흐름에 연결해 `COUNT DISTINCT`을 대조한다. 이 값이 chunk 단독 산출이라는 뜻은 아니다.
정상 예
정상 예에서는 source 순서와 owner 계약이 일치해 `COUNT DISTINCT`을 관찰한다.
틀린 예·반례
반례에서는 선행 guard·grain·stable order·cleanup을 생략한다. 동결 경계: COUNT DISTINCT만으로 금액 SUM 중복이 자동 해결되지는 않는다.
착각 방지
`원문 11–20줄`이 항목 전체 또는 외부 운영 Green을 단독 증명한다고 읽지 않는다.
하지 않는 일
이 chunk가 책임지지 않는 범위: COUNT DISTINCT만으로 금액 SUM 중복이 자동 해결되지는 않는다.
다음 연결
다음 source chunk의 입력 또는 exact local marker·SQL oracle·사람 검토 경계로 결과를 넘긴다.
F06-C03 · 원문 21–30줄
문법 해부
21~30줄의 `원문 21–30줄`을 입력·grain/guard·관찰·cleanup/stable output 단계로 나눈다.
실제 값 추적
항목 전체 흐름에 연결해 `pre-aggregate`을 대조한다. 이 값이 chunk 단독 산출이라는 뜻은 아니다.
정상 예
정상 예에서는 source 순서와 owner 계약이 일치해 `pre-aggregate`을 관찰한다.
틀린 예·반례
반례에서는 선행 guard·grain·stable order·cleanup을 생략한다. 동결 경계: audit_event의 nullable tx_id를 설명해야 한다.
착각 방지
`원문 21–30줄`이 항목 전체 또는 외부 운영 Green을 단독 증명한다고 읽지 않는다.
하지 않는 일
이 chunk가 책임지지 않는 범위: audit_event의 nullable tx_id를 설명해야 한다.
다음 연결
다음 source chunk의 입력 또는 exact local marker·SQL oracle·사람 검토 경계로 결과를 넘긴다.
F06-C04 · 원문 31–40줄
문법 해부
31~40줄의 `원문 31–40줄`을 입력·grain/guard·관찰·cleanup/stable output 단계로 나눈다.
실제 값 추적
항목 전체 흐름에 연결해 `transaction grain`을 대조한다. 이 값이 chunk 단독 산출이라는 뜻은 아니다.
정상 예
정상 예에서는 source 순서와 owner 계약이 일치해 `transaction grain`을 관찰한다.
틀린 예·반례
반례에서는 선행 guard·grain·stable order·cleanup을 생략한다. 동결 경계: 격리 반례는 production fixture가 아니다.
착각 방지
`원문 31–40줄`이 항목 전체 또는 외부 운영 Green을 단독 증명한다고 읽지 않는다.
하지 않는 일
이 chunk가 책임지지 않는 범위: 격리 반례는 production fixture가 아니다.
다음 연결
다음 source chunk의 입력 또는 exact local marker·SQL oracle·사람 검토 경계로 결과를 넘긴다.
반례히토리 → 니지카 → 료 → 키타
  1. 히토리

    겉보기에는 맞지만 깨지는 예는?

  2. 니지카

    COUNT(*)를 ledger 건수라고 부른다

  3. 그 상태는 입력 grain·owner·관찰 중 한 칸이 비어 있어.

  4. 키타

    수정한 뒤 같은 source bytes와 evidence를 다시 대조해.

08

STEP 08 / 13

실제 값 따라가기

같은 입력값이 어느 줄을 지나 어떤 결과가 되는지 추적합니다.

순서들어온 값코드가 하는 일나온 값·상태경계
F06-T01 raw1 tx, N ledger, M audittwo joinsN×M joined rowsCOUNT(*)는 child 수 아님
F06-T02 preaggregatechild tablesGROUP BY tx_idone row per child summary원본 상세 행은 사라짐
F06-T03 counterexample2 and 3 rowsCROSS JOIN6workbook 정본 답안 아님
책임 경계히토리 → 니지카 → 료 → 키타
  1. 히토리

    이 항목의 마지막 책임선은?

  2. 니지카

    직접 역할은 `비정본 Q37 JOIN grain 진단 SQL`이야.

  3. 대표 경계는 `격리 반례는 production fixture가 아니다`이야.

  4. 키타

    정본/학습용 label과 local/external owner까지 확인하면 끝이야.

09

STEP 09 / 13

Micrometer·RequestId·PowerShell·PostgreSQL 내부에서 벌어지는 일

Micrometer·JUnit·PowerShell·PostgreSQL·alert/runbook에서 실제로 일어나는 일과 증명 범위를 구분합니다.

relational join

조건을 만족하는 좌우 행 조합을 모두 만든다.

서로 다른 child cardinality를 자동 보호하지 않는다.
COUNT DISTINCT

증폭된 결과에서 unique child id를 센다.

SUM amount 중복을 자동 고치지는 않는다.
preaggregation

JOIN 전 grain을 parent key로 맞춘다.

원하는 output grain을 먼저 합의해야 한다.
10

STEP 10 / 13

흔한 착각과 틀린 예

그럴듯하지만 틀린 해석을 반례로 고칩니다.

❌ COUNT(*)를 ledger 건수라고 부른다

왜 틀리나 비정본 Q37 JOIN grain 진단 SQL의 grain·owner·관찰·경계 중 적어도 하나를 건너뛴다.

바르게 읽기 business_tx를 parent grain으로 선언한다. 그리고 source의 실제 값과 provenance를 다시 대조한다.

반례 반례에서는 `workbook 제공 정답이 아니다` 상태인데도 Green을 주장하게 된다.

❌ DISTINCT를 SELECT 전체에 붙이면 모든 집계가 해결된다고 본다

왜 틀리나 비정본 Q37 JOIN grain 진단 SQL의 grain·owner·관찰·경계 중 적어도 하나를 건너뛴다.

바르게 읽기 raw JOIN의 joined_rows와 distinct child 수를 비교한다. 그리고 source의 실제 값과 provenance를 다시 대조한다.

반례 반례에서는 `COUNT DISTINCT만으로 금액 SUM 중복이 자동 해결되지는 않는다` 상태인데도 Green을 주장하게 된다.

❌ 두 child를 raw JOIN한 뒤 amount를 SUM한다

왜 틀리나 비정본 Q37 JOIN grain 진단 SQL의 grain·owner·관찰·경계 중 적어도 하나를 건너뛴다.

바르게 읽기 각 child를 tx_id별로 선집계한다. 그리고 source의 실제 값과 provenance를 다시 대조한다.

반례 반례에서는 `audit_event의 nullable tx_id를 설명해야 한다` 상태인데도 Green을 주장하게 된다.

❌ LEFT JOIN을 쓰면 N×M이 사라진다고 본다

왜 틀리나 비정본 Q37 JOIN grain 진단 SQL의 grain·owner·관찰·경계 중 적어도 하나를 건너뛴다.

바르게 읽기 격리 2×3 반례에서 6행을 확인한다. 그리고 source의 실제 값과 provenance를 다시 대조한다.

반례 반례에서는 `격리 반례는 production fixture가 아니다` 상태인데도 Green을 주장하게 된다.

❌ Q37 예시를 workbook 정본 답안이라 부른다

왜 틀리나 비정본 Q37 JOIN grain 진단 SQL의 grain·owner·관찰·경계 중 적어도 하나를 건너뛴다.

바르게 읽기 격리 2×3 반례에서 6행을 확인한다. 그리고 source의 실제 값과 provenance를 다시 대조한다.

반례 반례에서는 `workbook 제공 정답이 아니다` 상태인데도 Green을 주장하게 된다.

11

STEP 11 / 13

이 코드가 보장하지 않는 것

이 코드가 책임지지 않는 일을 분리합니다.

직접 미보장

workbook 제공 정답이 아니다

이 책임을 맡는 곳: metric/query grain
직접 미보장

COUNT DISTINCT만으로 금액 SUM 중복이 자동 해결되지는 않는다

이 책임을 맡는 곳: 별도 local/external 실행
직접 미보장

audit_event의 nullable tx_id를 설명해야 한다

이 책임을 맡는 곳: secret·개인정보·운영 정책
직접 미보장

격리 반례는 production fixture가 아니다

이 책임을 맡는 곳: infrastructure·사람 검토
12

STEP 12 / 13

직접 다시 써보기

뜻 → 조각 → 전체 코드 순서로 다시 씁니다.

1단계 · 뜻부터 복원

다음 역할을 고정값과 미보장 경계까지 말한다: 두 1:N 자식을 생 JOIN할 때 N×M 행 폭증이 생기는 이유와 자식별 선집계 해법을 보여 주는 비정본 Q37 예시다.

2단계 · 코드 조각 재조립

  1. 원문 1–10줄
  2. 원문 11–20줄
  3. 원문 21–30줄
  4. 원문 31–40줄

3단계 · 파일 전체 다시 쓰기

40개 물리 줄을 원본 순서로 복원하고 SHA-256 cc87fecae930e197d9982e720550e86ca999d6fec30bde7362eed9d607a8de53와 대조한다.

자가 점검
  • 원본 source/template bytes와 줄 번호를 바꾸지 않았는가?
  • 정본 3개와 학습용 예시 8개를 구분했는가?
  • RequestId local Gate와 DB wait local drill의 Green 범위를 분리했는가?
  • dashboard·alert·incident timeline을 NOT_RUN_EXTERNAL 또는 사람 검토로 남겼는가?
  • Q37의 JOIN grain과 Q38의 SUCCESS·반개구간 가정을 드러냈는가?
13

STEP 13 / 13

전체 원본 source

감사로 고정한 전체 source를 가감 없이 확인합니다.

학습용 예시 전체 확인하기 · 정본 답안 아님
학습용 예시 · Q37/Q38 prompt 기반 SQL · 정본 답안 아님illustrative/sql/W23-SQL-Q37.sqlSHA-256 cc87fecae930e197d9982e720550e86ca999d6fec30bde7362eed9d607a8de53
W23-SQL-Q37 — 두 1:N JOIN의 N×M 증폭과 선집계 해법 전체
-- 학습용 예시 · 정본 답안 아님
-- 입력 grain: business_tx 1행/거래, ledger_entry 1행/원장 항목, audit_event 1행/감사 사건
-- 출력 grain: 거래 1행. 두 1:N 자식을 동시에 생으로 JOIN하면 N×M으로 행이 늘어날 수 있다.

SELECT tx.tx_id,
       COUNT(*) AS joined_rows,
       COUNT(DISTINCT le.entry_id) AS ledger_rows,
       COUNT(DISTINCT ae.audit_id) AS audit_rows
FROM business_tx AS tx
JOIN ledger_entry AS le ON le.tx_id = tx.tx_id
JOIN audit_event AS ae ON ae.tx_id = tx.tx_id
GROUP BY tx.tx_id
ORDER BY tx.tx_id;

-- 안전한 집계 예시: 각 1:N 자식을 거래 grain으로 먼저 줄인 뒤 JOIN한다.
WITH ledger_counts AS (
    SELECT tx_id, COUNT(*) AS ledger_rows
    FROM ledger_entry
    GROUP BY tx_id
),
audit_counts AS (
    SELECT tx_id, COUNT(*) AS audit_rows
    FROM audit_event
    WHERE tx_id IS NOT NULL
    GROUP BY tx_id
)
SELECT tx.tx_id,
       COALESCE(le.ledger_rows, 0) AS ledger_rows,
       COALESCE(ae.audit_rows, 0) AS audit_rows
FROM business_tx AS tx
LEFT JOIN ledger_counts AS le ON le.tx_id = tx.tx_id
LEFT JOIN audit_counts AS ae ON ae.tx_id = tx.tx_id
ORDER BY tx.tx_id;

-- 격리 반례: parent 1행 × child_a 2행 × child_b 3행 = JOIN 결과 6행.
WITH child_a(id) AS (VALUES (1), (2)),
child_b(id) AS (VALUES (10), (20), (30))
SELECT COUNT(*) AS multiplied_rows
FROM child_a
CROSS JOIN child_b;
07

run-w23-db-wait.ps1 — 실제 row-lock wait 1→0과 final value 2를 증명하는 정본 drill

scripts/run-w23-db-wait.ps1

원문 정본 · 완전한 packaged PowerShell source · 정본 · W23-F07
175줄 연결175줄 번역16 chunks
01

STEP 01 / 13

오늘 이 코드에서 해결할 문제

무엇을 이해해야 하는지 질문부터 잡습니다.

오늘의 한 문장

disposable PostgreSQL row lock wait를 만들고 관찰·해소·최종값·native exit·cleanup을 검증해 db-wait.json을 원자 발행하는 제공 정본 runner다.

  1. `scope=ROW_UPDATE`은 어느 줄에서 생기거나 검증될까?
  2. 입력→guard→관찰→cleanup 또는 stable output 순서는 무엇인가?
  3. local 자동 owner와 external human owner는 각각 누구인가?
  4. 이 source가 직접 관찰하지 않은 Green은 무엇인가?
  5. 반례는 `실제 운영 DB를 관찰하지 않는다` 경계와 어떻게 연결되는가?
이 파일에서 끝까지 다시 쓰는 값scope=ROW_UPDATEobserved=1cleared=0final_value=2native_exits=0 cleanup=1
02

STEP 02 / 13

아주 짧게: 이 코드는 왜 필요할까?

웹소설 대신 이 코드가 필요한 이유만 두 문단으로 쉽게 봅니다.

STARRY가 metric catalog·requestId 봉투·DB wait 영수증·alert/runbook·SQL grain 표를 서로 다른 칸에 놓는다.

run-w23-db-wait.ps1 — 실제 row-lock wait 1→0과 final value 2를 증명하는 정본 drill ― 관측 증거 흐름으로 바꾸기

disposable PostgreSQL row lock wait를 만들고 관찰·해소·최종값·native exit·cleanup을 검증해 db-wait.json을 원자 발행하는 제공 정본 runner다.

핵심값 scope=ROW_UPDATE, observed=1, cleared=0, final_value=2, native_exits=0 cleanup=1을 원본 줄로 따라가되, `실제 운영 DB를 관찰하지 않는다`까지 함께 표시해 local 관찰을 외부 운영 Green으로 부풀리지 않는다.

딱 여기까지만 비유는 grain·owner·순서를 기억하게 할 뿐 실제 Gradle/Docker/PostgreSQL 실행, dashboard·notification, 운영 SLA를 자동 증명하지 않는다.

03

STEP 03 / 13

초등학생도 이해하는 설명

생활 비유와 실제 코드의 경계를 함께 확인합니다.

원문 1–12줄

1~12줄을 한 덩어리로 읽어 1번째 움직임을 본다. disposable PostgreSQL row lock wait를 만들고 관찰·해소·최종값·native exit·cleanup을 검증해 db-wait.json을 원자 발행하는 제공 정본 runner다.

코드 연결
1~12줄
비유
한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험
비유의 끝
실제 운영 DB를 관찰하지 않는다

원문 13–24줄

13~24줄을 한 덩어리로 읽어 2번째 움직임을 본다. disposable PostgreSQL row lock wait를 만들고 관찰·해소·최종값·native exit·cleanup을 검증해 db-wait.json을 원자 발행하는 제공 정본 runner다.

코드 연결
13~24줄
비유
한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험
비유의 끝
Compose/Container와 Docker·PostgreSQL이 필요하다

원문 25–36줄

25~36줄을 한 덩어리로 읽어 3번째 움직임을 본다. disposable PostgreSQL row lock wait를 만들고 관찰·해소·최종값·native exit·cleanup을 검증해 db-wait.json을 원자 발행하는 제공 정본 runner다.

코드 연결
25~36줄
비유
한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험
비유의 끝
row-update lock 한 종류만 다룬다
문제의 첫 장면히토리 → 니지카 → 료 → 키타
  1. 히토리

    첫 고정값은 `scope=ROW_UPDATE` 맞아?

  2. 니지카

    disposable PostgreSQL row lock wait를 만들고 관찰·해소·최종값·native exit·cleanup을 검증해 db-wait.json을 원자 발행하는 제공 정본 runner다.

  3. 원문에서 `scope=ROW_UPDATE`이 만들어지거나 확인되는 줄을 찾자.

  4. 키타

    그리고 `실제 운영 DB를 관찰하지 않는다`도 같이 적어.

입력에서 결과까지히토리 → 니지카 → 료 → 키타
  1. 히토리

    `observed=1`은 언제 생겨?

  2. 니지카

    disposable schema와 value=0 fixture를 만든다. → holder와 waiter UPDATE를 별도 process로 시작한다.

  3. Lock wait와 blocking pid를 관찰한다. → wait=0·value=2·native exit=0·cleanup=1 뒤 evidence를 발행한다.

  4. 키타

    관찰값과 `Compose/Container와 Docker·PostgreSQL이 필요하다`을 분리하면 돼.

04

STEP 04 / 13

비유 ↔ 코드 전체 연결표

감사 규칙상 연결 대상인 원본 175줄을 빠짐없이 연결합니다.

단어 몇 개만 뽑은 표가 아닙니다.원문 정본 · 완전한 packaged PowerShell source에서 비어 있지 않은 모든 줄을 원본 줄 번호 그대로 연결했습니다.175 / 175 연결
정확한 원본 줄STARRY 비유실제 뜻·입력·결과·한계
1줄F07-L01 param( 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer의 1번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `scope=ROW_UPDATE` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
실제 운영 DB를 관찰하지 않는다
2줄F07-L02 [ValidateSet('Compose','Container')][string]$Mode = 'Compose', 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 DB wait runner의 lifecycle mode를 Compose와 Container 두 값으로 제한한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `observed=1` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
Compose/Container와 Docker·PostgreSQL이 필요하다
3줄F07-L03 [string]$ComposeProject = 'w23-db-wait-lab', 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer에서 `[string]$ComposeProject = 'w23-db-wait-lab',` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `cleared=0` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
row-update lock 한 종류만 다룬다
4줄F07-L04 [string]$Container = '', 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer에서 `[string]$Container = '',` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `final_value=2` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
외부 dashboard나 pool metric을 증명하지 않는다
5줄F07-L05 [Parameter(Mandatory = $true)][string]$EvidencePath 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer에서 `[Parameter(Mandatory = $true)][string]$EvidenceP` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `native_exits=0 cleanup=1` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
실제 운영 DB를 관찰하지 않는다
6줄F07-L06 ) 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 현재 object·array·block 또는 query 범위를 열거나 닫아 구조와 실행 순서를 유지한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `scope=ROW_UPDATE` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
Compose/Container와 Docker·PostgreSQL이 필요하다
8줄F07-L08 Set-StrictMode -Version Latest 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 미정의 변수 같은 PowerShell 오류를 조기에 드러낸다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `cleared=0` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
외부 dashboard나 pool metric을 증명하지 않는다
9줄F07-L09 $ErrorActionPreference = 'Stop' 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer에서 `$ErrorActionPreference = 'Stop'` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `final_value=2` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
실제 운영 DB를 관찰하지 않는다
11줄F07-L11 $root = Split-Path -Parent $PSScriptRoot 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer에서 `$root = Split-Path -Parent $PSScriptRoot` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `scope=ROW_UPDATE` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
row-update lock 한 종류만 다룬다
12줄F07-L12 $evidence = if ([IO.Path]::IsPathRooted($EvidencePath)) { 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer에서 `$evidence = if ([IO.Path]::IsPathRooted($Evidenc` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `observed=1` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
외부 dashboard나 pool metric을 증명하지 않는다
13줄F07-L13 [IO.Path]::GetFullPath($EvidencePath) 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer에서 `[IO.Path]::GetFullPath($EvidencePath)` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `cleared=0` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
실제 운영 DB를 관찰하지 않는다
14줄F07-L14 } else { 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer의 14번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `final_value=2` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
Compose/Container와 Docker·PostgreSQL이 필요하다
15줄F07-L15 [IO.Path]::GetFullPath((Join-Path $root $EvidencePath)) 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer에서 `[IO.Path]::GetFullPath((Join-Path $root $Evidenc` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `native_exits=0 cleanup=1` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
row-update lock 한 종류만 다룬다
16줄F07-L16 } 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 현재 object·array·block 또는 query 범위를 열거나 닫아 구조와 실행 순서를 유지한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `scope=ROW_UPDATE` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
외부 dashboard나 pool metric을 증명하지 않는다
17줄F07-L17 $compose = Join-Path $root 'compose.yaml' 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer에서 `$compose = Join-Path $root 'compose.yaml'` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `observed=1` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
실제 운영 DB를 관찰하지 않는다
18줄F07-L18 $runId = [guid]::NewGuid().ToString('N').Substring(0, 12) 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer에서 `$runId = [guid]::NewGuid().ToString('N').Substri` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `cleared=0` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
Compose/Container와 Docker·PostgreSQL이 필요하다
19줄F07-L19 $holderApp = "w23_holder_$runId" 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer에서 `$holderApp = "w23_holder_$runId"` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `final_value=2` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
row-update lock 한 종류만 다룬다
20줄F07-L20 $waiterApp = "w23_waiter_$runId" 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer에서 `$waiterApp = "w23_waiter_$runId"` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `native_exits=0 cleanup=1` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
외부 dashboard나 pool metric을 증명하지 않는다
21줄F07-L21 $holderSqlInContainer = "/tmp/w23-holder-$runId.sql" 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer에서 `$holderSqlInContainer = "/tmp/w23-holder-$runId.` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `scope=ROW_UPDATE` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
실제 운영 DB를 관찰하지 않는다
22줄F07-L22 $waiterSqlInContainer = "/tmp/w23-waiter-$runId.sql" 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer에서 `$waiterSqlInContainer = "/tmp/w23-waiter-$runId.` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `observed=1` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
Compose/Container와 Docker·PostgreSQL이 필요하다
23줄F07-L23 $holderSqlLocal = Join-Path $env:TEMP "w23-holder-$runId.sql" 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer에서 `$holderSqlLocal = Join-Path $env:TEMP "w23-holde` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `cleared=0` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
row-update lock 한 종류만 다룬다
24줄F07-L24 $waiterSqlLocal = Join-Path $env:TEMP "w23-waiter-$runId.sql" 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer에서 `$waiterSqlLocal = Join-Path $env:TEMP "w23-waite` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `final_value=2` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
외부 dashboard나 pool metric을 증명하지 않는다
25줄F07-L25 $holderOut = Join-Path $env:TEMP "w23-holder-$runId.out" 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer에서 `$holderOut = Join-Path $env:TEMP "w23-holder-$ru` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `native_exits=0 cleanup=1` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
실제 운영 DB를 관찰하지 않는다
26줄F07-L26 $holderErr = Join-Path $env:TEMP "w23-holder-$runId.err" 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer에서 `$holderErr = Join-Path $env:TEMP "w23-holder-$ru` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `scope=ROW_UPDATE` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
Compose/Container와 Docker·PostgreSQL이 필요하다
27줄F07-L27 $waiterOut = Join-Path $env:TEMP "w23-waiter-$runId.out" 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer에서 `$waiterOut = Join-Path $env:TEMP "w23-waiter-$ru` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `observed=1` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
row-update lock 한 종류만 다룬다
28줄F07-L28 $waiterErr = Join-Path $env:TEMP "w23-waiter-$runId.err" 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer에서 `$waiterErr = Join-Path $env:TEMP "w23-waiter-$ru` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `cleared=0` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
외부 dashboard나 pool metric을 증명하지 않는다
29줄F07-L29 $owned = $false 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer에서 `$owned = $false` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `final_value=2` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
실제 운영 DB를 관찰하지 않는다
30줄F07-L30 $fixtureCreated = $false 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer에서 `$fixtureCreated = $false` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `native_exits=0 cleanup=1` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
Compose/Container와 Docker·PostgreSQL이 필요하다
31줄F07-L31 $cleanup = $false 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer에서 `$cleanup = $false` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `scope=ROW_UPDATE` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
row-update lock 한 종류만 다룬다
32줄F07-L32 $holderProcess = $null 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer에서 `$holderProcess = $null` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `observed=1` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
외부 dashboard나 pool metric을 증명하지 않는다
33줄F07-L33 $waiterProcess = $null 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer에서 `$waiterProcess = $null` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `cleared=0` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
실제 운영 DB를 관찰하지 않는다
34줄F07-L34 $failure = $null 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer에서 `$failure = $null` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `final_value=2` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
Compose/Container와 Docker·PostgreSQL이 필요하다
35줄F07-L35 $body = $null 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer에서 `$body = $null` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `native_exits=0 cleanup=1` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
row-update lock 한 종류만 다룬다
37줄F07-L37 function Invoke-PsqlScalar([string]$Sql) { 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 native psql exit와 scalar output을 함께 검사하는 helper 경계를 연다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `observed=1` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
실제 운영 DB를 관찰하지 않는다
38줄F07-L38 $previousPreference = $ErrorActionPreference 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer에서 `$previousPreference = $ErrorActionPreference` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `cleared=0` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
Compose/Container와 Docker·PostgreSQL이 필요하다
39줄F07-L39 $ErrorActionPreference = 'Continue' 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer에서 `$ErrorActionPreference = 'Continue'` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `final_value=2` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
row-update lock 한 종류만 다룬다
40줄F07-L40 try { 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정상·실패 경로와 공통 cleanup/계측 경계를 분리하는 control-flow 블록이다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `native_exits=0 cleanup=1` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
외부 dashboard나 pool metric을 증명하지 않는다
41줄F07-L41 $rows = @(& docker exec $Container psql -X -q -A -t -v ON_ERROR_STOP=1 -U app -d financial_core -c $Sql 2>&1) 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer에서 `$rows = @(& docker exec $Container psql -X -q -A` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `scope=ROW_UPDATE` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
실제 운영 DB를 관찰하지 않는다
42줄F07-L42 $nativeExit = $LASTEXITCODE 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer에서 `$nativeExit = $LASTEXITCODE` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `observed=1` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
Compose/Container와 Docker·PostgreSQL이 필요하다
43줄F07-L43 } finally { 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer의 43번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `cleared=0` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
row-update lock 한 종류만 다룬다
44줄F07-L44 $ErrorActionPreference = $previousPreference 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer에서 `$ErrorActionPreference = $previousPreference` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `final_value=2` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
외부 dashboard나 pool metric을 증명하지 않는다
45줄F07-L45 } 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 현재 object·array·block 또는 query 범위를 열거나 닫아 구조와 실행 순서를 유지한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `native_exits=0 cleanup=1` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
실제 운영 DB를 관찰하지 않는다
46줄F07-L46 if ($nativeExit -ne 0) { throw "W23 psql failed: $($rows -join "`n")" } 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 선행 invariant가 깨졌을 때 evidence 발행 전에 멈추는 fail-closed guard다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `scope=ROW_UPDATE` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
Compose/Container와 Docker·PostgreSQL이 필요하다
47줄F07-L47 $values = @($rows | ForEach-Object { ([string]$_).Trim() } | Where-Object { $_ }) 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer에서 `$values = @($rows | ForEach-Object { ([string]$_` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `observed=1` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
row-update lock 한 종류만 다룬다
48줄F07-L48 if ($values.Count -lt 1) { throw 'W23 psql returned no scalar value' } 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 선행 invariant가 깨졌을 때 evidence 발행 전에 멈추는 fail-closed guard다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `cleared=0` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
외부 dashboard나 pool metric을 증명하지 않는다
49줄F07-L49 return $values[-1] 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer의 49번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `final_value=2` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
실제 운영 DB를 관찰하지 않는다
50줄F07-L50 } 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 현재 object·array·block 또는 query 범위를 열거나 닫아 구조와 실행 순서를 유지한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `native_exits=0 cleanup=1` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
Compose/Container와 Docker·PostgreSQL이 필요하다
52줄F07-L52 try { 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정상·실패 경로와 공통 cleanup/계측 경계를 분리하는 control-flow 블록이다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `observed=1` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
외부 dashboard나 pool metric을 증명하지 않는다
53줄F07-L53 if ($Mode -ceq 'Compose') { 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 선행 invariant가 깨졌을 때 evidence 발행 전에 멈추는 fail-closed guard다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `cleared=0` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
실제 운영 DB를 관찰하지 않는다
54줄F07-L54 if ($Container) { throw 'W23 Compose mode rejects Container' } 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 선행 invariant가 깨졌을 때 evidence 발행 전에 멈추는 fail-closed guard다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `final_value=2` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
Compose/Container와 Docker·PostgreSQL이 필요하다
55줄F07-L55 if ([string]::IsNullOrWhiteSpace($env:FCL_DB_PASSWORD)) { 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 선행 invariant가 깨졌을 때 evidence 발행 전에 멈추는 fail-closed guard다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `native_exits=0 cleanup=1` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
row-update lock 한 종류만 다룬다
56줄F07-L56 $env:FCL_DB_PASSWORD = 'w23-disposable-password' 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer에서 `$env:FCL_DB_PASSWORD = 'w23-disposable-password'` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `scope=ROW_UPDATE` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
외부 dashboard나 pool metric을 증명하지 않는다
57줄F07-L57 } 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 현재 object·array·block 또는 query 범위를 열거나 닫아 구조와 실행 순서를 유지한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `observed=1` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
실제 운영 DB를 관찰하지 않는다
58줄F07-L58 # Mark ownership before startup so partial Compose creation is always 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 이 source의 provenance·grain·가정·반례·실행 경계를 사람이 확인할 설명 줄이다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `cleared=0` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
Compose/Container와 Docker·PostgreSQL이 필요하다
59줄F07-L59 # torn down in finally, even when `up --wait` itself fails. 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 이 source의 provenance·grain·가정·반례·실행 경계를 사람이 확인할 설명 줄이다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `final_value=2` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
row-update lock 한 종류만 다룬다
60줄F07-L60 $owned = $true 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer에서 `$owned = $true` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `native_exits=0 cleanup=1` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
외부 dashboard나 pool metric을 증명하지 않는다
61줄F07-L61 & docker compose -f $compose -p $ComposeProject up -d --wait db 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer의 61번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `scope=ROW_UPDATE` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
실제 운영 DB를 관찰하지 않는다
62줄F07-L62 if ($LASTEXITCODE -ne 0) { throw "W23 compose up exit=$LASTEXITCODE" } 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 선행 invariant가 깨졌을 때 evidence 발행 전에 멈추는 fail-closed guard다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `observed=1` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
Compose/Container와 Docker·PostgreSQL이 필요하다
63줄F07-L63 $Container = (& docker compose -f $compose -p $ComposeProject ps -q db).Trim() 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer에서 `$Container = (& docker compose -f $compose -p $C` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `cleared=0` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
row-update lock 한 종류만 다룬다
64줄F07-L64 } elseif ([string]::IsNullOrWhiteSpace($Container)) { 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer에서 `} elseif ([string]::IsNullOrWhiteSpace($Containe` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `final_value=2` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
외부 dashboard나 pool metric을 증명하지 않는다
65줄F07-L65 throw 'W23 Container mode requires Container' 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 선행 invariant가 깨졌을 때 evidence 발행 전에 멈추는 fail-closed guard다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `native_exits=0 cleanup=1` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
실제 운영 DB를 관찰하지 않는다
66줄F07-L66 } 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 현재 object·array·block 또는 query 범위를 열거나 닫아 구조와 실행 순서를 유지한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `scope=ROW_UPDATE` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
Compose/Container와 Docker·PostgreSQL이 필요하다
67줄F07-L67 if ([string]::IsNullOrWhiteSpace($Container)) { throw 'W23 container resolution failed' } 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 선행 invariant가 깨졌을 때 evidence 발행 전에 멈추는 fail-closed guard다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `observed=1` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
row-update lock 한 종류만 다룬다
69줄F07-L69 $setup = "DROP SCHEMA IF EXISTS w23_wait CASCADE; CREATE SCHEMA w23_wait; CREATE TABLE w23_wait.probe(id int PRIMARY KEY,value int NOT NULL); INSERT INTO w23_wait.probe VALUES(1,0);" 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer에서 `$setup = "DROP SCHEMA IF EXISTS w23_wait CASCADE` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `final_value=2` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
실제 운영 DB를 관찰하지 않는다
70줄F07-L70 Invoke-PsqlScalar("$setup SELECT count(*) FROM w23_wait.probe;") | Out-Null 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 native psql exit와 scalar output을 함께 검사하는 helper 경계를 연다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `native_exits=0 cleanup=1` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
Compose/Container와 Docker·PostgreSQL이 필요하다
71줄F07-L71 $fixtureCreated = $true 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer에서 `$fixtureCreated = $true` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `scope=ROW_UPDATE` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
row-update lock 한 종류만 다룬다
73줄F07-L73 @" 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer의 73번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `cleared=0` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
실제 운영 DB를 관찰하지 않는다
74줄F07-L74 \set ON_ERROR_STOP on 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer의 74번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `final_value=2` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
Compose/Container와 Docker·PostgreSQL이 필요하다
75줄F07-L75 SET application_name='$holderApp'; 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 holder와 waiter session을 pg_stat_activity에서 정확히 찾을 고유 이름을 준다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `native_exits=0 cleanup=1` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
row-update lock 한 종류만 다룬다
76줄F07-L76 BEGIN; 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer의 76번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `scope=ROW_UPDATE` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
외부 dashboard나 pool metric을 증명하지 않는다
77줄F07-L77 UPDATE w23_wait.probe SET value=value+1 WHERE id=1; 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer에서 `UPDATE w23_wait.probe SET value=value+1 WHERE id` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `observed=1` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
실제 운영 DB를 관찰하지 않는다
78줄F07-L78 SELECT pg_sleep(6); 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 holder가 row lock을 잠시 유지해 waiter를 관찰할 시간을 만든다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `cleared=0` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
Compose/Container와 Docker·PostgreSQL이 필요하다
79줄F07-L79 COMMIT; 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer의 79번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `final_value=2` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
row-update lock 한 종류만 다룬다
80줄F07-L80 "@ | Set-Content -Encoding utf8 -LiteralPath $holderSqlLocal 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer의 80번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `native_exits=0 cleanup=1` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
외부 dashboard나 pool metric을 증명하지 않는다
81줄F07-L81 @" 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer의 81번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `scope=ROW_UPDATE` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
실제 운영 DB를 관찰하지 않는다
82줄F07-L82 \set ON_ERROR_STOP on 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer의 82번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `observed=1` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
Compose/Container와 Docker·PostgreSQL이 필요하다
83줄F07-L83 SET application_name='$waiterApp'; 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 holder와 waiter session을 pg_stat_activity에서 정확히 찾을 고유 이름을 준다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `cleared=0` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
row-update lock 한 종류만 다룬다
84줄F07-L84 SET lock_timeout='10s'; 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer에서 `SET lock_timeout='10s';` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `final_value=2` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
외부 dashboard나 pool metric을 증명하지 않는다
85줄F07-L85 UPDATE w23_wait.probe SET value=value+1 WHERE id=1; 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer에서 `UPDATE w23_wait.probe SET value=value+1 WHERE id` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `native_exits=0 cleanup=1` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
실제 운영 DB를 관찰하지 않는다
86줄F07-L86 "@ | Set-Content -Encoding utf8 -LiteralPath $waiterSqlLocal 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer의 86번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `scope=ROW_UPDATE` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
Compose/Container와 Docker·PostgreSQL이 필요하다
88줄F07-L88 & docker cp $holderSqlLocal "${Container}:$holderSqlInContainer" | Out-Null 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer에서 `& docker cp $holderSqlLocal "${Container}:$holde` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `cleared=0` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
외부 dashboard나 pool metric을 증명하지 않는다
89줄F07-L89 if ($LASTEXITCODE -ne 0) { throw 'W23 holder SQL copy failed' } 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 선행 invariant가 깨졌을 때 evidence 발행 전에 멈추는 fail-closed guard다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `final_value=2` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
실제 운영 DB를 관찰하지 않는다
90줄F07-L90 & docker cp $waiterSqlLocal "${Container}:$waiterSqlInContainer" | Out-Null 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer에서 `& docker cp $waiterSqlLocal "${Container}:$waite` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `native_exits=0 cleanup=1` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
Compose/Container와 Docker·PostgreSQL이 필요하다
91줄F07-L91 if ($LASTEXITCODE -ne 0) { throw 'W23 waiter SQL copy failed' } 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 선행 invariant가 깨졌을 때 evidence 발행 전에 멈추는 fail-closed guard다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `scope=ROW_UPDATE` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
row-update lock 한 종류만 다룬다
93줄F07-L93 $holderProcess = Start-Process docker -ArgumentList @( 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer에서 `$holderProcess = Start-Process docker -ArgumentL` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `cleared=0` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
실제 운영 DB를 관찰하지 않는다
94줄F07-L94 'exec',$Container,'psql','-X','-v','ON_ERROR_STOP=1','-U','app','-d','financial_core','-f',$holderSqlInContainer 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer에서 `'exec',$Container,'psql','-X','-v','ON_ERROR_STO` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `final_value=2` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
Compose/Container와 Docker·PostgreSQL이 필요하다
95줄F07-L95 ) -RedirectStandardOutput $holderOut -RedirectStandardError $holderErr -PassThru -WindowStyle Hidden 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer의 95번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `native_exits=0 cleanup=1` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
row-update lock 한 종류만 다룬다
96줄F07-L96 Start-Sleep -Seconds 1 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer의 96번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `scope=ROW_UPDATE` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
외부 dashboard나 pool metric을 증명하지 않는다
97줄F07-L97 $waiterProcess = Start-Process docker -ArgumentList @( 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer에서 `$waiterProcess = Start-Process docker -ArgumentL` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `observed=1` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
실제 운영 DB를 관찰하지 않는다
98줄F07-L98 'exec',$Container,'psql','-X','-v','ON_ERROR_STOP=1','-U','app','-d','financial_core','-f',$waiterSqlInContainer 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer에서 `'exec',$Container,'psql','-X','-v','ON_ERROR_STO` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `cleared=0` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
Compose/Container와 Docker·PostgreSQL이 필요하다
99줄F07-L99 ) -RedirectStandardOutput $waiterOut -RedirectStandardError $waiterErr -PassThru -WindowStyle Hidden 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer의 99번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `final_value=2` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
row-update lock 한 종류만 다룬다
100줄F07-L100 Start-Sleep -Seconds 1 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer의 100번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `native_exits=0 cleanup=1` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
외부 dashboard나 pool metric을 증명하지 않는다
102줄F07-L102 $snapshotRaw = Invoke-PsqlScalar( 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 native psql exit와 scalar output을 함께 검사하는 helper 경계를 연다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `observed=1` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
Compose/Container와 Docker·PostgreSQL이 필요하다
103줄F07-L103 "SELECT wait_event_type||'|'||coalesce(wait_event,'')||'|'||cardinality(pg_blocking_pids(pid)) FROM pg_stat_activity WHERE application_name='$waiterApp' AND wait_event_type='Lock';" 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 holder와 waiter session을 pg_stat_activity에서 정확히 찾을 고유 이름을 준다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `cleared=0` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
row-update lock 한 종류만 다룬다
104줄F07-L104 ) 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 현재 object·array·block 또는 query 범위를 열거나 닫아 구조와 실행 순서를 유지한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `final_value=2` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
외부 dashboard나 pool metric을 증명하지 않는다
105줄F07-L105 $snapshot = $snapshotRaw.Split('|') 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer에서 `$snapshot = $snapshotRaw.Split('|')` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `native_exits=0 cleanup=1` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
실제 운영 DB를 관찰하지 않는다
106줄F07-L106 if ($snapshot.Count -ne 3 -or $snapshot[0] -cne 'Lock' -or [int]$snapshot[2] -lt 1) { 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 선행 invariant가 깨졌을 때 evidence 발행 전에 멈추는 fail-closed guard다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `scope=ROW_UPDATE` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
Compose/Container와 Docker·PostgreSQL이 필요하다
107줄F07-L107 throw "W23 exact row-lock snapshot invalid: $snapshotRaw" 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 선행 invariant가 깨졌을 때 evidence 발행 전에 멈추는 fail-closed guard다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `observed=1` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
row-update lock 한 종류만 다룬다
108줄F07-L108 } 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 현재 object·array·block 또는 query 범위를 열거나 닫아 구조와 실행 순서를 유지한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `cleared=0` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
외부 dashboard나 pool metric을 증명하지 않는다
109줄F07-L109 $observed = 1 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 row-lock wait가 실제 snapshot에서 관찰됐다는 local evidence 값을 고정한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `final_value=2` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
실제 운영 DB를 관찰하지 않는다
111줄F07-L111 if (!$holderProcess.WaitForExit(15000) -or !$waiterProcess.WaitForExit(15000)) { 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 선행 invariant가 깨졌을 때 evidence 발행 전에 멈추는 fail-closed guard다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `scope=ROW_UPDATE` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
row-update lock 한 종류만 다룬다
112줄F07-L112 throw 'W23 native process timeout' 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 선행 invariant가 깨졌을 때 evidence 발행 전에 멈추는 fail-closed guard다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `observed=1` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
외부 dashboard나 pool metric을 증명하지 않는다
113줄F07-L113 } 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 현재 object·array·block 또는 query 범위를 열거나 닫아 구조와 실행 순서를 유지한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `cleared=0` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
실제 운영 DB를 관찰하지 않는다
114줄F07-L114 $holderProcess.WaitForExit(); $waiterProcess.WaitForExit() 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer의 114번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `final_value=2` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
Compose/Container와 Docker·PostgreSQL이 필요하다
115줄F07-L115 $holderProcess.Refresh(); $waiterProcess.Refresh() 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer의 115번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `native_exits=0 cleanup=1` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
row-update lock 한 종류만 다룬다
116줄F07-L116 $holderExit = [int]$holderProcess.ExitCode 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer에서 `$holderExit = [int]$holderProcess.ExitCode` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `scope=ROW_UPDATE` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
외부 dashboard나 pool metric을 증명하지 않는다
117줄F07-L117 $waiterExit = [int]$waiterProcess.ExitCode 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer에서 `$waiterExit = [int]$waiterProcess.ExitCode` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `observed=1` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
실제 운영 DB를 관찰하지 않는다
118줄F07-L118 if ($holderExit -ne 0 -or $waiterExit -ne 0) { 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 선행 invariant가 깨졌을 때 evidence 발행 전에 멈추는 fail-closed guard다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `cleared=0` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
Compose/Container와 Docker·PostgreSQL이 필요하다
119줄F07-L119 $errors = @( 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer에서 `$errors = @(` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `final_value=2` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
row-update lock 한 종류만 다룬다
120줄F07-L120 if (Test-Path $holderErr) { Get-Content -Raw $holderErr } 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 선행 invariant가 깨졌을 때 evidence 발행 전에 멈추는 fail-closed guard다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `native_exits=0 cleanup=1` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
외부 dashboard나 pool metric을 증명하지 않는다
121줄F07-L121 if (Test-Path $waiterErr) { Get-Content -Raw $waiterErr } 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 선행 invariant가 깨졌을 때 evidence 발행 전에 멈추는 fail-closed guard다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `scope=ROW_UPDATE` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
실제 운영 DB를 관찰하지 않는다
122줄F07-L122 ) -join "`n" 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer의 122번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `observed=1` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
Compose/Container와 Docker·PostgreSQL이 필요하다
123줄F07-L123 throw "W23 native process failure holder=$holderExit waiter=$waiterExit`n$errors" 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 선행 invariant가 깨졌을 때 evidence 발행 전에 멈추는 fail-closed guard다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `cleared=0` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
row-update lock 한 종류만 다룬다
124줄F07-L124 } 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 현재 object·array·block 또는 query 범위를 열거나 닫아 구조와 실행 순서를 유지한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `final_value=2` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
외부 dashboard나 pool metric을 증명하지 않는다
125줄F07-L125 $cleared = [int](Invoke-PsqlScalar("SELECT count(*) FROM pg_stat_activity WHERE application_name IN ('$holderApp','$waiterApp') AND wait_event_type='Lock';")) 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 native psql exit와 scalar output을 함께 검사하는 helper 경계를 연다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `native_exits=0 cleanup=1` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
실제 운영 DB를 관찰하지 않는다
126줄F07-L126 $finalValue = [int](Invoke-PsqlScalar('SELECT value FROM w23_wait.probe WHERE id=1;')) 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 native psql exit와 scalar output을 함께 검사하는 helper 경계를 연다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `scope=ROW_UPDATE` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
Compose/Container와 Docker·PostgreSQL이 필요하다
127줄F07-L127 if ($cleared -ne 0 -or $finalValue -ne 2) { 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 두 process 종료 뒤 남은 Lock wait 수를 다시 측정한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `observed=1` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
row-update lock 한 종류만 다룬다
128줄F07-L128 throw "W23 wait/final value mismatch cleared=$cleared value=$finalValue" 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 두 process 종료 뒤 남은 Lock wait 수를 다시 측정한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `cleared=0` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
외부 dashboard나 pool metric을 증명하지 않는다
129줄F07-L129 } 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 현재 object·array·block 또는 query 범위를 열거나 닫아 구조와 실행 순서를 유지한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `final_value=2` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
실제 운영 DB를 관찰하지 않는다
131줄F07-L131 $body = [ordered]@{ 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer에서 `$body = [ordered]@{` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `scope=ROW_UPDATE` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
row-update lock 한 종류만 다룬다
132줄F07-L132 run_id = $runId 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer에서 `run_id = $runId` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `observed=1` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
외부 dashboard나 pool metric을 증명하지 않는다
133줄F07-L133 holder_session = $holderApp 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer에서 `holder_session = $holderApp` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `cleared=0` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
실제 운영 DB를 관찰하지 않는다
134줄F07-L134 waiter_session = $waiterApp 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer에서 `waiter_session = $waiterApp` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `final_value=2` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
Compose/Container와 Docker·PostgreSQL이 필요하다
135줄F07-L135 fixture = 'w23_wait.probe(id=1,value=0)' 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer에서 `fixture = 'w23_wait.probe(id=1,value=0)'` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `native_exits=0 cleanup=1` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
row-update lock 한 종류만 다룬다
136줄F07-L136 lock_scope = 'ROW_UPDATE' 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer에서 `lock_scope = 'ROW_UPDATE'` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `scope=ROW_UPDATE` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
외부 dashboard나 pool metric을 증명하지 않는다
137줄F07-L137 observed = $observed 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer에서 `observed = $observed` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `observed=1` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
실제 운영 DB를 관찰하지 않는다
138줄F07-L138 cleared = $cleared 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 두 process 종료 뒤 남은 Lock wait 수를 다시 측정한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `cleared=0` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
Compose/Container와 Docker·PostgreSQL이 필요하다
139줄F07-L139 holder_exit = $holderExit 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer에서 `holder_exit = $holderExit` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `final_value=2` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
row-update lock 한 종류만 다룬다
140줄F07-L140 waiter_exit = $waiterExit 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer에서 `waiter_exit = $waiterExit` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `native_exits=0 cleanup=1` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
외부 dashboard나 pool metric을 증명하지 않는다
141줄F07-L141 native_exits = 0 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer에서 `native_exits = 0` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `scope=ROW_UPDATE` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
실제 운영 DB를 관찰하지 않는다
142줄F07-L142 final_value = $finalValue 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 두 UPDATE가 모두 commit되어 fixture value가 0에서 2가 됐는지 읽는다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `observed=1` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
Compose/Container와 Docker·PostgreSQL이 필요하다
143줄F07-L143 snapshot = [ordered]@{ 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer에서 `snapshot = [ordered]@{` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `cleared=0` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
row-update lock 한 종류만 다룬다
144줄F07-L144 wait_event_type = $snapshot[0] 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 snapshot이 추정이 아니라 PostgreSQL `Lock` wait인지 확인한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `final_value=2` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
외부 dashboard나 pool metric을 증명하지 않는다
145줄F07-L145 wait_event = $snapshot[1] 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer에서 `wait_event = $snapshot[1]` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `native_exits=0 cleanup=1` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
실제 운영 DB를 관찰하지 않는다
146줄F07-L146 blocking_session_count = [int]$snapshot[2] 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer에서 `blocking_session_count = [int]$snapshot[2]` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `scope=ROW_UPDATE` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
Compose/Container와 Docker·PostgreSQL이 필요하다
147줄F07-L147 query_redacted = 'UPDATE w23_wait.probe WHERE id=?' 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer에서 `query_redacted = 'UPDATE w23_wait.probe WHERE id` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `observed=1` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
row-update lock 한 종류만 다룬다
148줄F07-L148 } 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 현재 object·array·block 또는 query 범위를 열거나 닫아 구조와 실행 순서를 유지한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `cleared=0` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
외부 dashboard나 pool metric을 증명하지 않는다
149줄F07-L149 source_sha256 = (Get-FileHash -LiteralPath $MyInvocation.MyCommand.Path -Algorithm SHA256).Hash.ToLowerInvariant() 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer에서 `source_sha256 = (Get-FileHash -LiteralPath $MyIn` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `final_value=2` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
실제 운영 DB를 관찰하지 않는다
150줄F07-L150 } 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 현재 object·array·block 또는 query 범위를 열거나 닫아 구조와 실행 순서를 유지한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `native_exits=0 cleanup=1` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
Compose/Container와 Docker·PostgreSQL이 필요하다
151줄F07-L151 } catch { 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer의 151번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `scope=ROW_UPDATE` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
row-update lock 한 종류만 다룬다
152줄F07-L152 $failure = $_ 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer에서 `$failure = $_` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `observed=1` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
외부 dashboard나 pool metric을 증명하지 않는다
153줄F07-L153 } finally { 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer의 153번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `cleared=0` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
실제 운영 DB를 관찰하지 않는다
154줄F07-L154 foreach ($process in @($holderProcess,$waiterProcess)) { 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer의 154번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `final_value=2` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
Compose/Container와 Docker·PostgreSQL이 필요하다
155줄F07-L155 if ($null -ne $process -and !$process.HasExited) { 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 선행 invariant가 깨졌을 때 evidence 발행 전에 멈추는 fail-closed guard다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `native_exits=0 cleanup=1` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
row-update lock 한 종류만 다룬다
156줄F07-L156 Stop-Process -Id $process.Id -Force -ErrorAction SilentlyContinue 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer의 156번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `scope=ROW_UPDATE` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
외부 dashboard나 pool metric을 증명하지 않는다
157줄F07-L157 } 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 현재 object·array·block 또는 query 범위를 열거나 닫아 구조와 실행 순서를 유지한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `observed=1` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
실제 운영 DB를 관찰하지 않는다
158줄F07-L158 } 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 현재 object·array·block 또는 query 범위를 열거나 닫아 구조와 실행 순서를 유지한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `cleared=0` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
Compose/Container와 Docker·PostgreSQL이 필요하다
159줄F07-L159 $schemaCleanup = $true 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer에서 `$schemaCleanup = $true` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `final_value=2` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
row-update lock 한 종류만 다룬다
160줄F07-L160 if ($fixtureCreated -and ![string]::IsNullOrWhiteSpace($Container)) { 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 선행 invariant가 깨졌을 때 evidence 발행 전에 멈추는 fail-closed guard다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `native_exits=0 cleanup=1` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
외부 dashboard나 pool metric을 증명하지 않는다
161줄F07-L161 & docker exec $Container psql -X -q -v ON_ERROR_STOP=1 -U app -d financial_core -c 'DROP SCHEMA IF EXISTS w23_wait CASCADE;' | Out-Null 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer에서 `& docker exec $Container psql -X -q -v ON_ERROR_` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `scope=ROW_UPDATE` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
실제 운영 DB를 관찰하지 않는다
162줄F07-L162 $schemaCleanup = ($LASTEXITCODE -eq 0) 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer에서 `$schemaCleanup = ($LASTEXITCODE -eq 0)` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `observed=1` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
Compose/Container와 Docker·PostgreSQL이 필요하다
163줄F07-L163 & docker exec $Container rm -f $holderSqlInContainer $waiterSqlInContainer | Out-Null 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer의 163번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `cleared=0` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
row-update lock 한 종류만 다룬다
164줄F07-L164 } 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 현재 object·array·block 또는 query 범위를 열거나 닫아 구조와 실행 순서를 유지한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `final_value=2` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
외부 dashboard나 pool metric을 증명하지 않는다
165줄F07-L165 $composeCleanup = $true 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer에서 `$composeCleanup = $true` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `native_exits=0 cleanup=1` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
실제 운영 DB를 관찰하지 않는다
166줄F07-L166 if ($owned) { 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 선행 invariant가 깨졌을 때 evidence 발행 전에 멈추는 fail-closed guard다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `scope=ROW_UPDATE` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
Compose/Container와 Docker·PostgreSQL이 필요하다
167줄F07-L167 & docker compose -f $compose -p $ComposeProject down -v --remove-orphans | Out-Null 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer의 167번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `observed=1` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
row-update lock 한 종류만 다룬다
168줄F07-L168 $composeCleanup = ($LASTEXITCODE -eq 0) 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer에서 `$composeCleanup = ($LASTEXITCODE -eq 0)` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `cleared=0` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
외부 dashboard나 pool metric을 증명하지 않는다
169줄F07-L169 } 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 현재 object·array·block 또는 query 범위를 열거나 닫아 구조와 실행 순서를 유지한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `final_value=2` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
실제 운영 DB를 관찰하지 않는다
170줄F07-L170 $cleanup = $schemaCleanup -and $composeCleanup 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer에서 `$cleanup = $schemaCleanup -and $composeCleanup` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `native_exits=0 cleanup=1` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
Compose/Container와 Docker·PostgreSQL이 필요하다
171줄F07-L171 Remove-Item $holderSqlLocal,$waiterSqlLocal,$holderOut,$holderErr,$waiterOut,$waiterErr -Force -ErrorAction SilentlyContinue 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer의 171번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `scope=ROW_UPDATE` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
row-update lock 한 종류만 다룬다
172줄F07-L172 } 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 현재 object·array·block 또는 query 범위를 열거나 닫아 구조와 실행 순서를 유지한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `observed=1` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
외부 dashboard나 pool metric을 증명하지 않는다
174줄F07-L174 if (!$cleanup) { 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 선행 invariant가 깨졌을 때 evidence 발행 전에 멈추는 fail-closed guard다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `final_value=2` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
Compose/Container와 Docker·PostgreSQL이 필요하다
175줄F07-L175 if ($null -ne $failure) { 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 선행 invariant가 깨졌을 때 evidence 발행 전에 멈추는 fail-closed guard다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `native_exits=0 cleanup=1` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
row-update lock 한 종류만 다룬다
176줄F07-L176 throw "W23 DB wait failed and cleanup was not confirmed: $($failure.Exception.Message)" 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 선행 invariant가 깨졌을 때 evidence 발행 전에 멈추는 fail-closed guard다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `scope=ROW_UPDATE` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
외부 dashboard나 pool metric을 증명하지 않는다
177줄F07-L177 } 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 현재 object·array·block 또는 query 범위를 열거나 닫아 구조와 실행 순서를 유지한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `observed=1` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
실제 운영 DB를 관찰하지 않는다
178줄F07-L178 throw 'W23 DB wait cleanup was not confirmed' 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 선행 invariant가 깨졌을 때 evidence 발행 전에 멈추는 fail-closed guard다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `cleared=0` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
Compose/Container와 Docker·PostgreSQL이 필요하다
179줄F07-L179 } 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 현재 object·array·block 또는 query 범위를 열거나 닫아 구조와 실행 순서를 유지한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `final_value=2` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
row-update lock 한 종류만 다룬다
180줄F07-L180 if ($null -ne $failure) { throw $failure } 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 선행 invariant가 깨졌을 때 evidence 발행 전에 멈추는 fail-closed guard다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `native_exits=0 cleanup=1` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
외부 dashboard나 pool metric을 증명하지 않는다
181줄F07-L181 if ($null -eq $body) { throw 'W23 DB wait produced no result' } 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 선행 invariant가 깨졌을 때 evidence 발행 전에 멈추는 fail-closed guard다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `scope=ROW_UPDATE` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
실제 운영 DB를 관찰하지 않는다
183줄F07-L183 $body['cleanup'] = 1 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 schema·Compose cleanup이 확인된 뒤 evidence cleanup 값을 1로 넣는다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `cleared=0` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
row-update lock 한 종류만 다룬다
184줄F07-L184 New-Item -ItemType Directory -Force (Split-Path -Parent $evidence) | Out-Null 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer의 184번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `final_value=2` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
외부 dashboard나 pool metric을 증명하지 않는다
185줄F07-L185 $temporary = "$evidence.tmp" 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer에서 `$temporary = "$evidence.tmp"` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `native_exits=0 cleanup=1` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
실제 운영 DB를 관찰하지 않는다
186줄F07-L186 $body | ConvertTo-Json -Depth 6 | Set-Content -Encoding utf8 -LiteralPath $temporary 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer의 186번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `scope=ROW_UPDATE` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
Compose/Container와 Docker·PostgreSQL이 필요하다
187줄F07-L187 Move-Item -LiteralPath $temporary -Destination $evidence -Force 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 정본 PostgreSQL row-lock wait evidence producer의 187번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `observed=1` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
row-update lock 한 종류만 다룬다
189줄F07-L189 "W23_DB_WAIT_GREEN scope=ROW_UPDATE observed=1 cleared=0 final_value=2 native_exits=0 cleanup=1" 한 작업자가 서랍의 같은 행을 잡은 채 6초 기다리고, 둘째 작업자의 대기 표지판을 촬영한 뒤 두 작업이 끝나면 서랍 값 2와 빈 대기열을 확인하는 격리 실험 observed=1·cleared=0·value=2·native exits=0·cleanup=1을 닫는 exact marker다.
입력
disposable PostgreSQL container·evidence path·row fixture
결과·효과
이 줄 뒤에는 항목 전체의 `final_value=2` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
실제 운영 DB를 관찰하지 않는다
Green 범위히토리 → 니지카 → 료 → 키타
  1. 히토리

    marker나 문서가 보이면 W23 전체 성공이야?

  2. 니지카

    아니. 이 source가 직접 검증한 claim만 말해야 해.

  3. 직접 연결되는 대표 값은 `native_exits=0 cleanup=1`이야.

  4. 키타

    `row-update lock 한 종류만 다룬다`는 별도 실행·사람 증거가 필요해.

05

STEP 05 / 13

원본 코드 조각

원본을 16개 의미 조각으로 나누어 그대로 확인합니다.

파일을 한꺼번에 외우지 않고 실행 의미가 이어지는 작은 조각으로 봅니다. 아래 코드는 hash로 고정한 native 정본 source에서 그대로 잘랐습니다.

F07-C01 · 원문 1–12줄1–12줄
1–12줄 원본
param(
    [ValidateSet('Compose','Container')][string]$Mode = 'Compose',
    [string]$ComposeProject = 'w23-db-wait-lab',
    [string]$Container = '',
    [Parameter(Mandatory = $true)][string]$EvidencePath
)

Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'

$root = Split-Path -Parent $PSScriptRoot
$evidence = if ([IO.Path]::IsPathRooted($EvidencePath)) {
F07-C02 · 원문 13–24줄13–24줄
13–24줄 원본
    [IO.Path]::GetFullPath($EvidencePath)
} else {
    [IO.Path]::GetFullPath((Join-Path $root $EvidencePath))
}
$compose = Join-Path $root 'compose.yaml'
$runId = [guid]::NewGuid().ToString('N').Substring(0, 12)
$holderApp = "w23_holder_$runId"
$waiterApp = "w23_waiter_$runId"
$holderSqlInContainer = "/tmp/w23-holder-$runId.sql"
$waiterSqlInContainer = "/tmp/w23-waiter-$runId.sql"
$holderSqlLocal = Join-Path $env:TEMP "w23-holder-$runId.sql"
$waiterSqlLocal = Join-Path $env:TEMP "w23-waiter-$runId.sql"
F07-C03 · 원문 25–36줄25–36줄
25–36줄 원본
$holderOut = Join-Path $env:TEMP "w23-holder-$runId.out"
$holderErr = Join-Path $env:TEMP "w23-holder-$runId.err"
$waiterOut = Join-Path $env:TEMP "w23-waiter-$runId.out"
$waiterErr = Join-Path $env:TEMP "w23-waiter-$runId.err"
$owned = $false
$fixtureCreated = $false
$cleanup = $false
$holderProcess = $null
$waiterProcess = $null
$failure = $null
$body = $null
F07-C04 · 원문 37–48줄37–48줄
37–48줄 원본
function Invoke-PsqlScalar([string]$Sql) {
    $previousPreference = $ErrorActionPreference
    $ErrorActionPreference = 'Continue'
    try {
        $rows = @(& docker exec $Container psql -X -q -A -t -v ON_ERROR_STOP=1 -U app -d financial_core -c $Sql 2>&1)
        $nativeExit = $LASTEXITCODE
    } finally {
        $ErrorActionPreference = $previousPreference
    }
    if ($nativeExit -ne 0) { throw "W23 psql failed: $($rows -join "`n")" }
    $values = @($rows | ForEach-Object { ([string]$_).Trim() } | Where-Object { $_ })
    if ($values.Count -lt 1) { throw 'W23 psql returned no scalar value' }
F07-C05 · 원문 49–60줄49–60줄
49–60줄 원본
    return $values[-1]
}

try {
    if ($Mode -ceq 'Compose') {
        if ($Container) { throw 'W23 Compose mode rejects Container' }
        if ([string]::IsNullOrWhiteSpace($env:FCL_DB_PASSWORD)) {
            $env:FCL_DB_PASSWORD = 'w23-disposable-password'
        }
        # Mark ownership before startup so partial Compose creation is always
        # torn down in finally, even when `up --wait` itself fails.
        $owned = $true
F07-C06 · 원문 61–72줄61–72줄
61–72줄 원본
        & docker compose -f $compose -p $ComposeProject up -d --wait db
        if ($LASTEXITCODE -ne 0) { throw "W23 compose up exit=$LASTEXITCODE" }
        $Container = (& docker compose -f $compose -p $ComposeProject ps -q db).Trim()
    } elseif ([string]::IsNullOrWhiteSpace($Container)) {
        throw 'W23 Container mode requires Container'
    }
    if ([string]::IsNullOrWhiteSpace($Container)) { throw 'W23 container resolution failed' }

    $setup = "DROP SCHEMA IF EXISTS w23_wait CASCADE; CREATE SCHEMA w23_wait; CREATE TABLE w23_wait.probe(id int PRIMARY KEY,value int NOT NULL); INSERT INTO w23_wait.probe VALUES(1,0);"
    Invoke-PsqlScalar("$setup SELECT count(*) FROM w23_wait.probe;") | Out-Null
    $fixtureCreated = $true
F07-C07 · 원문 73–84줄73–84줄
73–84줄 원본
    @"
\set ON_ERROR_STOP on
SET application_name='$holderApp';
BEGIN;
UPDATE w23_wait.probe SET value=value+1 WHERE id=1;
SELECT pg_sleep(6);
COMMIT;
"@ | Set-Content -Encoding utf8 -LiteralPath $holderSqlLocal
    @"
\set ON_ERROR_STOP on
SET application_name='$waiterApp';
SET lock_timeout='10s';
F07-C08 · 원문 85–96줄85–96줄
85–96줄 원본
UPDATE w23_wait.probe SET value=value+1 WHERE id=1;
"@ | Set-Content -Encoding utf8 -LiteralPath $waiterSqlLocal

    & docker cp $holderSqlLocal "${Container}:$holderSqlInContainer" | Out-Null
    if ($LASTEXITCODE -ne 0) { throw 'W23 holder SQL copy failed' }
    & docker cp $waiterSqlLocal "${Container}:$waiterSqlInContainer" | Out-Null
    if ($LASTEXITCODE -ne 0) { throw 'W23 waiter SQL copy failed' }

    $holderProcess = Start-Process docker -ArgumentList @(
        'exec',$Container,'psql','-X','-v','ON_ERROR_STOP=1','-U','app','-d','financial_core','-f',$holderSqlInContainer
    ) -RedirectStandardOutput $holderOut -RedirectStandardError $holderErr -PassThru -WindowStyle Hidden
    Start-Sleep -Seconds 1
F07-C09 · 원문 97–108줄97–108줄
97–108줄 원본
    $waiterProcess = Start-Process docker -ArgumentList @(
        'exec',$Container,'psql','-X','-v','ON_ERROR_STOP=1','-U','app','-d','financial_core','-f',$waiterSqlInContainer
    ) -RedirectStandardOutput $waiterOut -RedirectStandardError $waiterErr -PassThru -WindowStyle Hidden
    Start-Sleep -Seconds 1

    $snapshotRaw = Invoke-PsqlScalar(
        "SELECT wait_event_type||'|'||coalesce(wait_event,'')||'|'||cardinality(pg_blocking_pids(pid)) FROM pg_stat_activity WHERE application_name='$waiterApp' AND wait_event_type='Lock';"
    )
    $snapshot = $snapshotRaw.Split('|')
    if ($snapshot.Count -ne 3 -or $snapshot[0] -cne 'Lock' -or [int]$snapshot[2] -lt 1) {
        throw "W23 exact row-lock snapshot invalid: $snapshotRaw"
    }
F07-C10 · 원문 109–120줄109–120줄
109–120줄 원본
    $observed = 1

    if (!$holderProcess.WaitForExit(15000) -or !$waiterProcess.WaitForExit(15000)) {
        throw 'W23 native process timeout'
    }
    $holderProcess.WaitForExit(); $waiterProcess.WaitForExit()
    $holderProcess.Refresh(); $waiterProcess.Refresh()
    $holderExit = [int]$holderProcess.ExitCode
    $waiterExit = [int]$waiterProcess.ExitCode
    if ($holderExit -ne 0 -or $waiterExit -ne 0) {
        $errors = @(
            if (Test-Path $holderErr) { Get-Content -Raw $holderErr }
F07-C11 · 원문 121–132줄121–132줄
121–132줄 원본
            if (Test-Path $waiterErr) { Get-Content -Raw $waiterErr }
        ) -join "`n"
        throw "W23 native process failure holder=$holderExit waiter=$waiterExit`n$errors"
    }
    $cleared = [int](Invoke-PsqlScalar("SELECT count(*) FROM pg_stat_activity WHERE application_name IN ('$holderApp','$waiterApp') AND wait_event_type='Lock';"))
    $finalValue = [int](Invoke-PsqlScalar('SELECT value FROM w23_wait.probe WHERE id=1;'))
    if ($cleared -ne 0 -or $finalValue -ne 2) {
        throw "W23 wait/final value mismatch cleared=$cleared value=$finalValue"
    }

    $body = [ordered]@{
        run_id = $runId
F07-C12 · 원문 133–144줄133–144줄
133–144줄 원본
        holder_session = $holderApp
        waiter_session = $waiterApp
        fixture = 'w23_wait.probe(id=1,value=0)'
        lock_scope = 'ROW_UPDATE'
        observed = $observed
        cleared = $cleared
        holder_exit = $holderExit
        waiter_exit = $waiterExit
        native_exits = 0
        final_value = $finalValue
        snapshot = [ordered]@{
            wait_event_type = $snapshot[0]
F07-C13 · 원문 145–156줄145–156줄
145–156줄 원본
            wait_event = $snapshot[1]
            blocking_session_count = [int]$snapshot[2]
            query_redacted = 'UPDATE w23_wait.probe WHERE id=?'
        }
        source_sha256 = (Get-FileHash -LiteralPath $MyInvocation.MyCommand.Path -Algorithm SHA256).Hash.ToLowerInvariant()
    }
} catch {
    $failure = $_
} finally {
    foreach ($process in @($holderProcess,$waiterProcess)) {
        if ($null -ne $process -and !$process.HasExited) {
            Stop-Process -Id $process.Id -Force -ErrorAction SilentlyContinue
F07-C14 · 원문 157–168줄157–168줄
157–168줄 원본
        }
    }
    $schemaCleanup = $true
    if ($fixtureCreated -and ![string]::IsNullOrWhiteSpace($Container)) {
        & docker exec $Container psql -X -q -v ON_ERROR_STOP=1 -U app -d financial_core -c 'DROP SCHEMA IF EXISTS w23_wait CASCADE;' | Out-Null
        $schemaCleanup = ($LASTEXITCODE -eq 0)
        & docker exec $Container rm -f $holderSqlInContainer $waiterSqlInContainer | Out-Null
    }
    $composeCleanup = $true
    if ($owned) {
        & docker compose -f $compose -p $ComposeProject down -v --remove-orphans | Out-Null
        $composeCleanup = ($LASTEXITCODE -eq 0)
F07-C15 · 원문 169–180줄169–180줄
169–180줄 원본
    }
    $cleanup = $schemaCleanup -and $composeCleanup
    Remove-Item $holderSqlLocal,$waiterSqlLocal,$holderOut,$holderErr,$waiterOut,$waiterErr -Force -ErrorAction SilentlyContinue
}

if (!$cleanup) {
    if ($null -ne $failure) {
        throw "W23 DB wait failed and cleanup was not confirmed: $($failure.Exception.Message)"
    }
    throw 'W23 DB wait cleanup was not confirmed'
}
if ($null -ne $failure) { throw $failure }
F07-C16 · 원문 181–189줄181–189줄
181–189줄 원본
if ($null -eq $body) { throw 'W23 DB wait produced no result' }

$body['cleanup'] = 1
New-Item -ItemType Directory -Force (Split-Path -Parent $evidence) | Out-Null
$temporary = "$evidence.tmp"
$body | ConvertTo-Json -Depth 6 | Set-Content -Encoding utf8 -LiteralPath $temporary
Move-Item -LiteralPath $temporary -Destination $evidence -Force

"W23_DB_WAIT_GREEN scope=ROW_UPDATE observed=1 cleared=0 final_value=2 native_exits=0 cleanup=1"
06

STEP 06 / 13

코드 한 줄씩 한국어로 번역

비어 있지 않은 175줄을 모두 한국어로 옮깁니다.

전체 번역 175 / 175

비어 있지 않은 원본 줄은 하나도 생략하지 않습니다.

원본한국어 번역
1param(정본 PostgreSQL row-lock wait evidence producer의 1번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
2 [ValidateSet('Compose','Container')][string]$Mode = 'Compose',DB wait runner의 lifecycle mode를 Compose와 Container 두 값으로 제한한다.
3 [string]$ComposeProject = 'w23-db-wait-lab',정본 PostgreSQL row-lock wait evidence producer에서 `[string]$ComposeProject = 'w23-db-wait-lab',` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
4 [string]$Container = '',정본 PostgreSQL row-lock wait evidence producer에서 `[string]$Container = '',` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
5 [Parameter(Mandatory = $true)][string]$EvidencePath정본 PostgreSQL row-lock wait evidence producer에서 `[Parameter(Mandatory = $true)][string]$EvidenceP` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
6)현재 object·array·block 또는 query 범위를 열거나 닫아 구조와 실행 순서를 유지한다.
8Set-StrictMode -Version Latest미정의 변수 같은 PowerShell 오류를 조기에 드러낸다.
9$ErrorActionPreference = 'Stop'정본 PostgreSQL row-lock wait evidence producer에서 `$ErrorActionPreference = 'Stop'` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
11$root = Split-Path -Parent $PSScriptRoot정본 PostgreSQL row-lock wait evidence producer에서 `$root = Split-Path -Parent $PSScriptRoot` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
12$evidence = if ([IO.Path]::IsPathRooted($EvidencePath)) {정본 PostgreSQL row-lock wait evidence producer에서 `$evidence = if ([IO.Path]::IsPathRooted($Evidenc` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
13 [IO.Path]::GetFullPath($EvidencePath)정본 PostgreSQL row-lock wait evidence producer에서 `[IO.Path]::GetFullPath($EvidencePath)` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
14} else {정본 PostgreSQL row-lock wait evidence producer의 14번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
15 [IO.Path]::GetFullPath((Join-Path $root $EvidencePath))정본 PostgreSQL row-lock wait evidence producer에서 `[IO.Path]::GetFullPath((Join-Path $root $Evidenc` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
16}현재 object·array·block 또는 query 범위를 열거나 닫아 구조와 실행 순서를 유지한다.
17$compose = Join-Path $root 'compose.yaml'정본 PostgreSQL row-lock wait evidence producer에서 `$compose = Join-Path $root 'compose.yaml'` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
18$runId = [guid]::NewGuid().ToString('N').Substring(0, 12)정본 PostgreSQL row-lock wait evidence producer에서 `$runId = [guid]::NewGuid().ToString('N').Substri` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
19$holderApp = "w23_holder_$runId"정본 PostgreSQL row-lock wait evidence producer에서 `$holderApp = "w23_holder_$runId"` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
20$waiterApp = "w23_waiter_$runId"정본 PostgreSQL row-lock wait evidence producer에서 `$waiterApp = "w23_waiter_$runId"` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
21$holderSqlInContainer = "/tmp/w23-holder-$runId.sql"정본 PostgreSQL row-lock wait evidence producer에서 `$holderSqlInContainer = "/tmp/w23-holder-$runId.` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
22$waiterSqlInContainer = "/tmp/w23-waiter-$runId.sql"정본 PostgreSQL row-lock wait evidence producer에서 `$waiterSqlInContainer = "/tmp/w23-waiter-$runId.` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
23$holderSqlLocal = Join-Path $env:TEMP "w23-holder-$runId.sql"정본 PostgreSQL row-lock wait evidence producer에서 `$holderSqlLocal = Join-Path $env:TEMP "w23-holde` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
24$waiterSqlLocal = Join-Path $env:TEMP "w23-waiter-$runId.sql"정본 PostgreSQL row-lock wait evidence producer에서 `$waiterSqlLocal = Join-Path $env:TEMP "w23-waite` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
25$holderOut = Join-Path $env:TEMP "w23-holder-$runId.out"정본 PostgreSQL row-lock wait evidence producer에서 `$holderOut = Join-Path $env:TEMP "w23-holder-$ru` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
26$holderErr = Join-Path $env:TEMP "w23-holder-$runId.err"정본 PostgreSQL row-lock wait evidence producer에서 `$holderErr = Join-Path $env:TEMP "w23-holder-$ru` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
27$waiterOut = Join-Path $env:TEMP "w23-waiter-$runId.out"정본 PostgreSQL row-lock wait evidence producer에서 `$waiterOut = Join-Path $env:TEMP "w23-waiter-$ru` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
28$waiterErr = Join-Path $env:TEMP "w23-waiter-$runId.err"정본 PostgreSQL row-lock wait evidence producer에서 `$waiterErr = Join-Path $env:TEMP "w23-waiter-$ru` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
29$owned = $false정본 PostgreSQL row-lock wait evidence producer에서 `$owned = $false` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
30$fixtureCreated = $false정본 PostgreSQL row-lock wait evidence producer에서 `$fixtureCreated = $false` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
31$cleanup = $false정본 PostgreSQL row-lock wait evidence producer에서 `$cleanup = $false` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
32$holderProcess = $null정본 PostgreSQL row-lock wait evidence producer에서 `$holderProcess = $null` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
33$waiterProcess = $null정본 PostgreSQL row-lock wait evidence producer에서 `$waiterProcess = $null` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
34$failure = $null정본 PostgreSQL row-lock wait evidence producer에서 `$failure = $null` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
35$body = $null정본 PostgreSQL row-lock wait evidence producer에서 `$body = $null` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
37function Invoke-PsqlScalar([string]$Sql) {native psql exit와 scalar output을 함께 검사하는 helper 경계를 연다.
38 $previousPreference = $ErrorActionPreference정본 PostgreSQL row-lock wait evidence producer에서 `$previousPreference = $ErrorActionPreference` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
39 $ErrorActionPreference = 'Continue'정본 PostgreSQL row-lock wait evidence producer에서 `$ErrorActionPreference = 'Continue'` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
40 try {정상·실패 경로와 공통 cleanup/계측 경계를 분리하는 control-flow 블록이다.
41 $rows = @(& docker exec $Container psql -X -q -A -t -v ON_ERROR_STOP=1 -U app -d financial_core -c $Sql 2>&1)정본 PostgreSQL row-lock wait evidence producer에서 `$rows = @(& docker exec $Container psql -X -q -A` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
42 $nativeExit = $LASTEXITCODE정본 PostgreSQL row-lock wait evidence producer에서 `$nativeExit = $LASTEXITCODE` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
43 } finally {정본 PostgreSQL row-lock wait evidence producer의 43번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
44 $ErrorActionPreference = $previousPreference정본 PostgreSQL row-lock wait evidence producer에서 `$ErrorActionPreference = $previousPreference` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
45 }현재 object·array·block 또는 query 범위를 열거나 닫아 구조와 실행 순서를 유지한다.
46 if ($nativeExit -ne 0) { throw "W23 psql failed: $($rows -join "`n")" }선행 invariant가 깨졌을 때 evidence 발행 전에 멈추는 fail-closed guard다.
47 $values = @($rows | ForEach-Object { ([string]$_).Trim() } | Where-Object { $_ })정본 PostgreSQL row-lock wait evidence producer에서 `$values = @($rows | ForEach-Object { ([string]$_` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
48 if ($values.Count -lt 1) { throw 'W23 psql returned no scalar value' }선행 invariant가 깨졌을 때 evidence 발행 전에 멈추는 fail-closed guard다.
49 return $values[-1]정본 PostgreSQL row-lock wait evidence producer의 49번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
50}현재 object·array·block 또는 query 범위를 열거나 닫아 구조와 실행 순서를 유지한다.
52try {정상·실패 경로와 공통 cleanup/계측 경계를 분리하는 control-flow 블록이다.
53 if ($Mode -ceq 'Compose') {선행 invariant가 깨졌을 때 evidence 발행 전에 멈추는 fail-closed guard다.
54 if ($Container) { throw 'W23 Compose mode rejects Container' }선행 invariant가 깨졌을 때 evidence 발행 전에 멈추는 fail-closed guard다.
55 if ([string]::IsNullOrWhiteSpace($env:FCL_DB_PASSWORD)) {선행 invariant가 깨졌을 때 evidence 발행 전에 멈추는 fail-closed guard다.
56 $env:FCL_DB_PASSWORD = 'w23-disposable-password'정본 PostgreSQL row-lock wait evidence producer에서 `$env:FCL_DB_PASSWORD = 'w23-disposable-password'` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
57 }현재 object·array·block 또는 query 범위를 열거나 닫아 구조와 실행 순서를 유지한다.
58 # Mark ownership before startup so partial Compose creation is always이 source의 provenance·grain·가정·반례·실행 경계를 사람이 확인할 설명 줄이다.
59 # torn down in finally, even when `up --wait` itself fails.이 source의 provenance·grain·가정·반례·실행 경계를 사람이 확인할 설명 줄이다.
60 $owned = $true정본 PostgreSQL row-lock wait evidence producer에서 `$owned = $true` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
61 & docker compose -f $compose -p $ComposeProject up -d --wait db정본 PostgreSQL row-lock wait evidence producer의 61번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
62 if ($LASTEXITCODE -ne 0) { throw "W23 compose up exit=$LASTEXITCODE" }선행 invariant가 깨졌을 때 evidence 발행 전에 멈추는 fail-closed guard다.
63 $Container = (& docker compose -f $compose -p $ComposeProject ps -q db).Trim()정본 PostgreSQL row-lock wait evidence producer에서 `$Container = (& docker compose -f $compose -p $C` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
64 } elseif ([string]::IsNullOrWhiteSpace($Container)) {정본 PostgreSQL row-lock wait evidence producer에서 `} elseif ([string]::IsNullOrWhiteSpace($Containe` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
65 throw 'W23 Container mode requires Container'선행 invariant가 깨졌을 때 evidence 발행 전에 멈추는 fail-closed guard다.
66 }현재 object·array·block 또는 query 범위를 열거나 닫아 구조와 실행 순서를 유지한다.
67 if ([string]::IsNullOrWhiteSpace($Container)) { throw 'W23 container resolution failed' }선행 invariant가 깨졌을 때 evidence 발행 전에 멈추는 fail-closed guard다.
69 $setup = "DROP SCHEMA IF EXISTS w23_wait CASCADE; CREATE SCHEMA w23_wait; CREATE TABLE w23_wait.probe(id int PRIMARY KEY,value int NOT NULL); INSERT INTO w23_wait.probe VALUES(1,0);"정본 PostgreSQL row-lock wait evidence producer에서 `$setup = "DROP SCHEMA IF EXISTS w23_wait CASCADE` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
70 Invoke-PsqlScalar("$setup SELECT count(*) FROM w23_wait.probe;") | Out-Nullnative psql exit와 scalar output을 함께 검사하는 helper 경계를 연다.
71 $fixtureCreated = $true정본 PostgreSQL row-lock wait evidence producer에서 `$fixtureCreated = $true` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
73 @"정본 PostgreSQL row-lock wait evidence producer의 73번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
74\set ON_ERROR_STOP on정본 PostgreSQL row-lock wait evidence producer의 74번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
75SET application_name='$holderApp';holder와 waiter session을 pg_stat_activity에서 정확히 찾을 고유 이름을 준다.
76BEGIN;정본 PostgreSQL row-lock wait evidence producer의 76번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
77UPDATE w23_wait.probe SET value=value+1 WHERE id=1;정본 PostgreSQL row-lock wait evidence producer에서 `UPDATE w23_wait.probe SET value=value+1 WHERE id` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
78SELECT pg_sleep(6);holder가 row lock을 잠시 유지해 waiter를 관찰할 시간을 만든다.
79COMMIT;정본 PostgreSQL row-lock wait evidence producer의 79번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
80"@ | Set-Content -Encoding utf8 -LiteralPath $holderSqlLocal정본 PostgreSQL row-lock wait evidence producer의 80번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
81 @"정본 PostgreSQL row-lock wait evidence producer의 81번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
82\set ON_ERROR_STOP on정본 PostgreSQL row-lock wait evidence producer의 82번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
83SET application_name='$waiterApp';holder와 waiter session을 pg_stat_activity에서 정확히 찾을 고유 이름을 준다.
84SET lock_timeout='10s';정본 PostgreSQL row-lock wait evidence producer에서 `SET lock_timeout='10s';` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
85UPDATE w23_wait.probe SET value=value+1 WHERE id=1;정본 PostgreSQL row-lock wait evidence producer에서 `UPDATE w23_wait.probe SET value=value+1 WHERE id` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
86"@ | Set-Content -Encoding utf8 -LiteralPath $waiterSqlLocal정본 PostgreSQL row-lock wait evidence producer의 86번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
88 & docker cp $holderSqlLocal "${Container}:$holderSqlInContainer" | Out-Null정본 PostgreSQL row-lock wait evidence producer에서 `& docker cp $holderSqlLocal "${Container}:$holde` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
89 if ($LASTEXITCODE -ne 0) { throw 'W23 holder SQL copy failed' }선행 invariant가 깨졌을 때 evidence 발행 전에 멈추는 fail-closed guard다.
90 & docker cp $waiterSqlLocal "${Container}:$waiterSqlInContainer" | Out-Null정본 PostgreSQL row-lock wait evidence producer에서 `& docker cp $waiterSqlLocal "${Container}:$waite` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
91 if ($LASTEXITCODE -ne 0) { throw 'W23 waiter SQL copy failed' }선행 invariant가 깨졌을 때 evidence 발행 전에 멈추는 fail-closed guard다.
93 $holderProcess = Start-Process docker -ArgumentList @(정본 PostgreSQL row-lock wait evidence producer에서 `$holderProcess = Start-Process docker -ArgumentL` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
94 'exec',$Container,'psql','-X','-v','ON_ERROR_STOP=1','-U','app','-d','financial_core','-f',$holderSqlInContainer정본 PostgreSQL row-lock wait evidence producer에서 `'exec',$Container,'psql','-X','-v','ON_ERROR_STO` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
95 ) -RedirectStandardOutput $holderOut -RedirectStandardError $holderErr -PassThru -WindowStyle Hidden정본 PostgreSQL row-lock wait evidence producer의 95번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
96 Start-Sleep -Seconds 1정본 PostgreSQL row-lock wait evidence producer의 96번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
97 $waiterProcess = Start-Process docker -ArgumentList @(정본 PostgreSQL row-lock wait evidence producer에서 `$waiterProcess = Start-Process docker -ArgumentL` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
98 'exec',$Container,'psql','-X','-v','ON_ERROR_STOP=1','-U','app','-d','financial_core','-f',$waiterSqlInContainer정본 PostgreSQL row-lock wait evidence producer에서 `'exec',$Container,'psql','-X','-v','ON_ERROR_STO` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
99 ) -RedirectStandardOutput $waiterOut -RedirectStandardError $waiterErr -PassThru -WindowStyle Hidden정본 PostgreSQL row-lock wait evidence producer의 99번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
100 Start-Sleep -Seconds 1정본 PostgreSQL row-lock wait evidence producer의 100번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
102 $snapshotRaw = Invoke-PsqlScalar(native psql exit와 scalar output을 함께 검사하는 helper 경계를 연다.
103 "SELECT wait_event_type||'|'||coalesce(wait_event,'')||'|'||cardinality(pg_blocking_pids(pid)) FROM pg_stat_activity WHERE application_name='$waiterApp' AND wait_event_type='Lock';"holder와 waiter session을 pg_stat_activity에서 정확히 찾을 고유 이름을 준다.
104 )현재 object·array·block 또는 query 범위를 열거나 닫아 구조와 실행 순서를 유지한다.
105 $snapshot = $snapshotRaw.Split('|')정본 PostgreSQL row-lock wait evidence producer에서 `$snapshot = $snapshotRaw.Split('|')` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
106 if ($snapshot.Count -ne 3 -or $snapshot[0] -cne 'Lock' -or [int]$snapshot[2] -lt 1) {선행 invariant가 깨졌을 때 evidence 발행 전에 멈추는 fail-closed guard다.
107 throw "W23 exact row-lock snapshot invalid: $snapshotRaw"선행 invariant가 깨졌을 때 evidence 발행 전에 멈추는 fail-closed guard다.
108 }현재 object·array·block 또는 query 범위를 열거나 닫아 구조와 실행 순서를 유지한다.
109 $observed = 1row-lock wait가 실제 snapshot에서 관찰됐다는 local evidence 값을 고정한다.
111 if (!$holderProcess.WaitForExit(15000) -or !$waiterProcess.WaitForExit(15000)) {선행 invariant가 깨졌을 때 evidence 발행 전에 멈추는 fail-closed guard다.
112 throw 'W23 native process timeout'선행 invariant가 깨졌을 때 evidence 발행 전에 멈추는 fail-closed guard다.
113 }현재 object·array·block 또는 query 범위를 열거나 닫아 구조와 실행 순서를 유지한다.
114 $holderProcess.WaitForExit(); $waiterProcess.WaitForExit()정본 PostgreSQL row-lock wait evidence producer의 114번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
115 $holderProcess.Refresh(); $waiterProcess.Refresh()정본 PostgreSQL row-lock wait evidence producer의 115번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
116 $holderExit = [int]$holderProcess.ExitCode정본 PostgreSQL row-lock wait evidence producer에서 `$holderExit = [int]$holderProcess.ExitCode` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
117 $waiterExit = [int]$waiterProcess.ExitCode정본 PostgreSQL row-lock wait evidence producer에서 `$waiterExit = [int]$waiterProcess.ExitCode` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
118 if ($holderExit -ne 0 -or $waiterExit -ne 0) {선행 invariant가 깨졌을 때 evidence 발행 전에 멈추는 fail-closed guard다.
119 $errors = @(정본 PostgreSQL row-lock wait evidence producer에서 `$errors = @(` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
120 if (Test-Path $holderErr) { Get-Content -Raw $holderErr }선행 invariant가 깨졌을 때 evidence 발행 전에 멈추는 fail-closed guard다.
121 if (Test-Path $waiterErr) { Get-Content -Raw $waiterErr }선행 invariant가 깨졌을 때 evidence 발행 전에 멈추는 fail-closed guard다.
122 ) -join "`n"정본 PostgreSQL row-lock wait evidence producer의 122번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
123 throw "W23 native process failure holder=$holderExit waiter=$waiterExit`n$errors"선행 invariant가 깨졌을 때 evidence 발행 전에 멈추는 fail-closed guard다.
124 }현재 object·array·block 또는 query 범위를 열거나 닫아 구조와 실행 순서를 유지한다.
125 $cleared = [int](Invoke-PsqlScalar("SELECT count(*) FROM pg_stat_activity WHERE application_name IN ('$holderApp','$waiterApp') AND wait_event_type='Lock';"))native psql exit와 scalar output을 함께 검사하는 helper 경계를 연다.
126 $finalValue = [int](Invoke-PsqlScalar('SELECT value FROM w23_wait.probe WHERE id=1;'))native psql exit와 scalar output을 함께 검사하는 helper 경계를 연다.
127 if ($cleared -ne 0 -or $finalValue -ne 2) {두 process 종료 뒤 남은 Lock wait 수를 다시 측정한다.
128 throw "W23 wait/final value mismatch cleared=$cleared value=$finalValue"두 process 종료 뒤 남은 Lock wait 수를 다시 측정한다.
129 }현재 object·array·block 또는 query 범위를 열거나 닫아 구조와 실행 순서를 유지한다.
131 $body = [ordered]@{정본 PostgreSQL row-lock wait evidence producer에서 `$body = [ordered]@{` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
132 run_id = $runId정본 PostgreSQL row-lock wait evidence producer에서 `run_id = $runId` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
133 holder_session = $holderApp정본 PostgreSQL row-lock wait evidence producer에서 `holder_session = $holderApp` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
134 waiter_session = $waiterApp정본 PostgreSQL row-lock wait evidence producer에서 `waiter_session = $waiterApp` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
135 fixture = 'w23_wait.probe(id=1,value=0)'정본 PostgreSQL row-lock wait evidence producer에서 `fixture = 'w23_wait.probe(id=1,value=0)'` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
136 lock_scope = 'ROW_UPDATE'정본 PostgreSQL row-lock wait evidence producer에서 `lock_scope = 'ROW_UPDATE'` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
137 observed = $observed정본 PostgreSQL row-lock wait evidence producer에서 `observed = $observed` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
138 cleared = $cleared두 process 종료 뒤 남은 Lock wait 수를 다시 측정한다.
139 holder_exit = $holderExit정본 PostgreSQL row-lock wait evidence producer에서 `holder_exit = $holderExit` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
140 waiter_exit = $waiterExit정본 PostgreSQL row-lock wait evidence producer에서 `waiter_exit = $waiterExit` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
141 native_exits = 0정본 PostgreSQL row-lock wait evidence producer에서 `native_exits = 0` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
142 final_value = $finalValue두 UPDATE가 모두 commit되어 fixture value가 0에서 2가 됐는지 읽는다.
143 snapshot = [ordered]@{정본 PostgreSQL row-lock wait evidence producer에서 `snapshot = [ordered]@{` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
144 wait_event_type = $snapshot[0]snapshot이 추정이 아니라 PostgreSQL `Lock` wait인지 확인한다.
145 wait_event = $snapshot[1]정본 PostgreSQL row-lock wait evidence producer에서 `wait_event = $snapshot[1]` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
146 blocking_session_count = [int]$snapshot[2]정본 PostgreSQL row-lock wait evidence producer에서 `blocking_session_count = [int]$snapshot[2]` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
147 query_redacted = 'UPDATE w23_wait.probe WHERE id=?'정본 PostgreSQL row-lock wait evidence producer에서 `query_redacted = 'UPDATE w23_wait.probe WHERE id` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
148 }현재 object·array·block 또는 query 범위를 열거나 닫아 구조와 실행 순서를 유지한다.
149 source_sha256 = (Get-FileHash -LiteralPath $MyInvocation.MyCommand.Path -Algorithm SHA256).Hash.ToLowerInvariant()정본 PostgreSQL row-lock wait evidence producer에서 `source_sha256 = (Get-FileHash -LiteralPath $MyIn` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
150 }현재 object·array·block 또는 query 범위를 열거나 닫아 구조와 실행 순서를 유지한다.
151} catch {정본 PostgreSQL row-lock wait evidence producer의 151번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
152 $failure = $_정본 PostgreSQL row-lock wait evidence producer에서 `$failure = $_` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
153} finally {정본 PostgreSQL row-lock wait evidence producer의 153번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
154 foreach ($process in @($holderProcess,$waiterProcess)) {정본 PostgreSQL row-lock wait evidence producer의 154번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
155 if ($null -ne $process -and !$process.HasExited) {선행 invariant가 깨졌을 때 evidence 발행 전에 멈추는 fail-closed guard다.
156 Stop-Process -Id $process.Id -Force -ErrorAction SilentlyContinue정본 PostgreSQL row-lock wait evidence producer의 156번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
157 }현재 object·array·block 또는 query 범위를 열거나 닫아 구조와 실행 순서를 유지한다.
158 }현재 object·array·block 또는 query 범위를 열거나 닫아 구조와 실행 순서를 유지한다.
159 $schemaCleanup = $true정본 PostgreSQL row-lock wait evidence producer에서 `$schemaCleanup = $true` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
160 if ($fixtureCreated -and ![string]::IsNullOrWhiteSpace($Container)) {선행 invariant가 깨졌을 때 evidence 발행 전에 멈추는 fail-closed guard다.
161 & docker exec $Container psql -X -q -v ON_ERROR_STOP=1 -U app -d financial_core -c 'DROP SCHEMA IF EXISTS w23_wait CASCADE;' | Out-Null정본 PostgreSQL row-lock wait evidence producer에서 `& docker exec $Container psql -X -q -v ON_ERROR_` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
162 $schemaCleanup = ($LASTEXITCODE -eq 0)정본 PostgreSQL row-lock wait evidence producer에서 `$schemaCleanup = ($LASTEXITCODE -eq 0)` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
163 & docker exec $Container rm -f $holderSqlInContainer $waiterSqlInContainer | Out-Null정본 PostgreSQL row-lock wait evidence producer의 163번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
164 }현재 object·array·block 또는 query 범위를 열거나 닫아 구조와 실행 순서를 유지한다.
165 $composeCleanup = $true정본 PostgreSQL row-lock wait evidence producer에서 `$composeCleanup = $true` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
166 if ($owned) {선행 invariant가 깨졌을 때 evidence 발행 전에 멈추는 fail-closed guard다.
167 & docker compose -f $compose -p $ComposeProject down -v --remove-orphans | Out-Null정본 PostgreSQL row-lock wait evidence producer의 167번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
168 $composeCleanup = ($LASTEXITCODE -eq 0)정본 PostgreSQL row-lock wait evidence producer에서 `$composeCleanup = ($LASTEXITCODE -eq 0)` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
169 }현재 object·array·block 또는 query 범위를 열거나 닫아 구조와 실행 순서를 유지한다.
170 $cleanup = $schemaCleanup -and $composeCleanup정본 PostgreSQL row-lock wait evidence producer에서 `$cleanup = $schemaCleanup -and $composeCleanup` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
171 Remove-Item $holderSqlLocal,$waiterSqlLocal,$holderOut,$holderErr,$waiterOut,$waiterErr -Force -ErrorAction SilentlyContinue정본 PostgreSQL row-lock wait evidence producer의 171번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
172}현재 object·array·block 또는 query 범위를 열거나 닫아 구조와 실행 순서를 유지한다.
174if (!$cleanup) {선행 invariant가 깨졌을 때 evidence 발행 전에 멈추는 fail-closed guard다.
175 if ($null -ne $failure) {선행 invariant가 깨졌을 때 evidence 발행 전에 멈추는 fail-closed guard다.
176 throw "W23 DB wait failed and cleanup was not confirmed: $($failure.Exception.Message)"선행 invariant가 깨졌을 때 evidence 발행 전에 멈추는 fail-closed guard다.
177 }현재 object·array·block 또는 query 범위를 열거나 닫아 구조와 실행 순서를 유지한다.
178 throw 'W23 DB wait cleanup was not confirmed'선행 invariant가 깨졌을 때 evidence 발행 전에 멈추는 fail-closed guard다.
179}현재 object·array·block 또는 query 범위를 열거나 닫아 구조와 실행 순서를 유지한다.
180if ($null -ne $failure) { throw $failure }선행 invariant가 깨졌을 때 evidence 발행 전에 멈추는 fail-closed guard다.
181if ($null -eq $body) { throw 'W23 DB wait produced no result' }선행 invariant가 깨졌을 때 evidence 발행 전에 멈추는 fail-closed guard다.
183$body['cleanup'] = 1schema·Compose cleanup이 확인된 뒤 evidence cleanup 값을 1로 넣는다.
184New-Item -ItemType Directory -Force (Split-Path -Parent $evidence) | Out-Null정본 PostgreSQL row-lock wait evidence producer의 184번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
185$temporary = "$evidence.tmp"정본 PostgreSQL row-lock wait evidence producer에서 `$temporary = "$evidence.tmp"` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
186$body | ConvertTo-Json -Depth 6 | Set-Content -Encoding utf8 -LiteralPath $temporary정본 PostgreSQL row-lock wait evidence producer의 186번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
187Move-Item -LiteralPath $temporary -Destination $evidence -Force정본 PostgreSQL row-lock wait evidence producer의 187번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
189"W23_DB_WAIT_GREEN scope=ROW_UPDATE observed=1 cleared=0 final_value=2 native_exits=0 cleanup=1"observed=1·cleared=0·value=2·native exits=0·cleanup=1을 닫는 exact marker다.
07

STEP 07 / 13

기존 수준의 한 줄 읽기·문법 해부

쉬운 설명 다음에 문법과 실행 순서를 정밀하게 읽습니다.

한 줄로 읽기

disposable PostgreSQL row lock wait를 만들고 관찰·해소·최종값·native exit·cleanup을 검증해 db-wait.json을 원자 발행하는 제공 정본 runner다. 다만 실제 운영 DB를 관찰하지 않는다

문법 해부

  • Compose mode는 runner가 container lifecycle을 소유하고 Container mode는 caller 소유 container를 빌린다. canonical source의 실험은 UPDATE 대 UPDATE `ROW_UPDATE`다.
  • PDF p766의 `ACCESS EXCLUSIVE/SELECT` descriptor는 stale 설명이므로 canonical runner의 pg_stat_activity snapshot과 exact marker를 우선한다.

실행 순서

  1. disposable schema와 value=0 fixture를 만든다.
  2. holder와 waiter UPDATE를 별도 process로 시작한다.
  3. Lock wait와 blocking pid를 관찰한다.
  4. wait=0·value=2·native exit=0·cleanup=1 뒤 evidence를 발행한다.

W23 조각별 정밀 해설

F07-C01 · 원문 1–12줄
문법 해부
1~12줄의 `원문 1–12줄`을 입력·grain/guard·관찰·cleanup/stable output 단계로 나눈다.
실제 값 추적
항목 전체 흐름에 연결해 `scope=ROW_UPDATE`을 대조한다. 이 값이 chunk 단독 산출이라는 뜻은 아니다.
정상 예
정상 예에서는 source 순서와 owner 계약이 일치해 `scope=ROW_UPDATE`을 관찰한다.
틀린 예·반례
반례에서는 선행 guard·grain·stable order·cleanup을 생략한다. 동결 경계: 실제 운영 DB를 관찰하지 않는다.
착각 방지
`원문 1–12줄`이 항목 전체 또는 외부 운영 Green을 단독 증명한다고 읽지 않는다.
하지 않는 일
이 chunk가 책임지지 않는 범위: 실제 운영 DB를 관찰하지 않는다.
다음 연결
다음 source chunk의 입력 또는 exact local marker·SQL oracle·사람 검토 경계로 결과를 넘긴다.
F07-C02 · 원문 13–24줄
문법 해부
13~24줄의 `원문 13–24줄`을 입력·grain/guard·관찰·cleanup/stable output 단계로 나눈다.
실제 값 추적
항목 전체 흐름에 연결해 `observed=1`을 대조한다. 이 값이 chunk 단독 산출이라는 뜻은 아니다.
정상 예
정상 예에서는 source 순서와 owner 계약이 일치해 `observed=1`을 관찰한다.
틀린 예·반례
반례에서는 선행 guard·grain·stable order·cleanup을 생략한다. 동결 경계: Compose/Container와 Docker·PostgreSQL이 필요하다.
착각 방지
`원문 13–24줄`이 항목 전체 또는 외부 운영 Green을 단독 증명한다고 읽지 않는다.
하지 않는 일
이 chunk가 책임지지 않는 범위: Compose/Container와 Docker·PostgreSQL이 필요하다.
다음 연결
다음 source chunk의 입력 또는 exact local marker·SQL oracle·사람 검토 경계로 결과를 넘긴다.
F07-C03 · 원문 25–36줄
문법 해부
25~36줄의 `원문 25–36줄`을 입력·grain/guard·관찰·cleanup/stable output 단계로 나눈다.
실제 값 추적
항목 전체 흐름에 연결해 `cleared=0`을 대조한다. 이 값이 chunk 단독 산출이라는 뜻은 아니다.
정상 예
정상 예에서는 source 순서와 owner 계약이 일치해 `cleared=0`을 관찰한다.
틀린 예·반례
반례에서는 선행 guard·grain·stable order·cleanup을 생략한다. 동결 경계: row-update lock 한 종류만 다룬다.
착각 방지
`원문 25–36줄`이 항목 전체 또는 외부 운영 Green을 단독 증명한다고 읽지 않는다.
하지 않는 일
이 chunk가 책임지지 않는 범위: row-update lock 한 종류만 다룬다.
다음 연결
다음 source chunk의 입력 또는 exact local marker·SQL oracle·사람 검토 경계로 결과를 넘긴다.
F07-C04 · 원문 37–48줄
문법 해부
37~48줄의 `원문 37–48줄`을 입력·grain/guard·관찰·cleanup/stable output 단계로 나눈다.
실제 값 추적
항목 전체 흐름에 연결해 `final_value=2`을 대조한다. 이 값이 chunk 단독 산출이라는 뜻은 아니다.
정상 예
정상 예에서는 source 순서와 owner 계약이 일치해 `final_value=2`을 관찰한다.
틀린 예·반례
반례에서는 선행 guard·grain·stable order·cleanup을 생략한다. 동결 경계: 외부 dashboard나 pool metric을 증명하지 않는다.
착각 방지
`원문 37–48줄`이 항목 전체 또는 외부 운영 Green을 단독 증명한다고 읽지 않는다.
하지 않는 일
이 chunk가 책임지지 않는 범위: 외부 dashboard나 pool metric을 증명하지 않는다.
다음 연결
다음 source chunk의 입력 또는 exact local marker·SQL oracle·사람 검토 경계로 결과를 넘긴다.
F07-C05 · 원문 49–60줄
문법 해부
49~60줄의 `원문 49–60줄`을 입력·grain/guard·관찰·cleanup/stable output 단계로 나눈다.
실제 값 추적
항목 전체 흐름에 연결해 `native_exits=0 cleanup=1`을 대조한다. 이 값이 chunk 단독 산출이라는 뜻은 아니다.
정상 예
정상 예에서는 source 순서와 owner 계약이 일치해 `native_exits=0 cleanup=1`을 관찰한다.
틀린 예·반례
반례에서는 선행 guard·grain·stable order·cleanup을 생략한다. 동결 경계: 실제 운영 DB를 관찰하지 않는다.
착각 방지
`원문 49–60줄`이 항목 전체 또는 외부 운영 Green을 단독 증명한다고 읽지 않는다.
하지 않는 일
이 chunk가 책임지지 않는 범위: 실제 운영 DB를 관찰하지 않는다.
다음 연결
다음 source chunk의 입력 또는 exact local marker·SQL oracle·사람 검토 경계로 결과를 넘긴다.
F07-C06 · 원문 61–72줄
문법 해부
61~72줄의 `원문 61–72줄`을 입력·grain/guard·관찰·cleanup/stable output 단계로 나눈다.
실제 값 추적
항목 전체 흐름에 연결해 `scope=ROW_UPDATE`을 대조한다. 이 값이 chunk 단독 산출이라는 뜻은 아니다.
정상 예
정상 예에서는 source 순서와 owner 계약이 일치해 `scope=ROW_UPDATE`을 관찰한다.
틀린 예·반례
반례에서는 선행 guard·grain·stable order·cleanup을 생략한다. 동결 경계: Compose/Container와 Docker·PostgreSQL이 필요하다.
착각 방지
`원문 61–72줄`이 항목 전체 또는 외부 운영 Green을 단독 증명한다고 읽지 않는다.
하지 않는 일
이 chunk가 책임지지 않는 범위: Compose/Container와 Docker·PostgreSQL이 필요하다.
다음 연결
다음 source chunk의 입력 또는 exact local marker·SQL oracle·사람 검토 경계로 결과를 넘긴다.
F07-C07 · 원문 73–84줄
문법 해부
73~84줄의 `원문 73–84줄`을 입력·grain/guard·관찰·cleanup/stable output 단계로 나눈다.
실제 값 추적
항목 전체 흐름에 연결해 `observed=1`을 대조한다. 이 값이 chunk 단독 산출이라는 뜻은 아니다.
정상 예
정상 예에서는 source 순서와 owner 계약이 일치해 `observed=1`을 관찰한다.
틀린 예·반례
반례에서는 선행 guard·grain·stable order·cleanup을 생략한다. 동결 경계: row-update lock 한 종류만 다룬다.
착각 방지
`원문 73–84줄`이 항목 전체 또는 외부 운영 Green을 단독 증명한다고 읽지 않는다.
하지 않는 일
이 chunk가 책임지지 않는 범위: row-update lock 한 종류만 다룬다.
다음 연결
다음 source chunk의 입력 또는 exact local marker·SQL oracle·사람 검토 경계로 결과를 넘긴다.
F07-C08 · 원문 85–96줄
문법 해부
85~96줄의 `원문 85–96줄`을 입력·grain/guard·관찰·cleanup/stable output 단계로 나눈다.
실제 값 추적
항목 전체 흐름에 연결해 `cleared=0`을 대조한다. 이 값이 chunk 단독 산출이라는 뜻은 아니다.
정상 예
정상 예에서는 source 순서와 owner 계약이 일치해 `cleared=0`을 관찰한다.
틀린 예·반례
반례에서는 선행 guard·grain·stable order·cleanup을 생략한다. 동결 경계: 외부 dashboard나 pool metric을 증명하지 않는다.
착각 방지
`원문 85–96줄`이 항목 전체 또는 외부 운영 Green을 단독 증명한다고 읽지 않는다.
하지 않는 일
이 chunk가 책임지지 않는 범위: 외부 dashboard나 pool metric을 증명하지 않는다.
다음 연결
다음 source chunk의 입력 또는 exact local marker·SQL oracle·사람 검토 경계로 결과를 넘긴다.
F07-C09 · 원문 97–108줄
문법 해부
97~108줄의 `원문 97–108줄`을 입력·grain/guard·관찰·cleanup/stable output 단계로 나눈다.
실제 값 추적
항목 전체 흐름에 연결해 `final_value=2`을 대조한다. 이 값이 chunk 단독 산출이라는 뜻은 아니다.
정상 예
정상 예에서는 source 순서와 owner 계약이 일치해 `final_value=2`을 관찰한다.
틀린 예·반례
반례에서는 선행 guard·grain·stable order·cleanup을 생략한다. 동결 경계: 실제 운영 DB를 관찰하지 않는다.
착각 방지
`원문 97–108줄`이 항목 전체 또는 외부 운영 Green을 단독 증명한다고 읽지 않는다.
하지 않는 일
이 chunk가 책임지지 않는 범위: 실제 운영 DB를 관찰하지 않는다.
다음 연결
다음 source chunk의 입력 또는 exact local marker·SQL oracle·사람 검토 경계로 결과를 넘긴다.
F07-C10 · 원문 109–120줄
문법 해부
109~120줄의 `원문 109–120줄`을 입력·grain/guard·관찰·cleanup/stable output 단계로 나눈다.
실제 값 추적
항목 전체 흐름에 연결해 `native_exits=0 cleanup=1`을 대조한다. 이 값이 chunk 단독 산출이라는 뜻은 아니다.
정상 예
정상 예에서는 source 순서와 owner 계약이 일치해 `native_exits=0 cleanup=1`을 관찰한다.
틀린 예·반례
반례에서는 선행 guard·grain·stable order·cleanup을 생략한다. 동결 경계: Compose/Container와 Docker·PostgreSQL이 필요하다.
착각 방지
`원문 109–120줄`이 항목 전체 또는 외부 운영 Green을 단독 증명한다고 읽지 않는다.
하지 않는 일
이 chunk가 책임지지 않는 범위: Compose/Container와 Docker·PostgreSQL이 필요하다.
다음 연결
다음 source chunk의 입력 또는 exact local marker·SQL oracle·사람 검토 경계로 결과를 넘긴다.
F07-C11 · 원문 121–132줄
문법 해부
121~132줄의 `원문 121–132줄`을 입력·grain/guard·관찰·cleanup/stable output 단계로 나눈다.
실제 값 추적
항목 전체 흐름에 연결해 `scope=ROW_UPDATE`을 대조한다. 이 값이 chunk 단독 산출이라는 뜻은 아니다.
정상 예
정상 예에서는 source 순서와 owner 계약이 일치해 `scope=ROW_UPDATE`을 관찰한다.
틀린 예·반례
반례에서는 선행 guard·grain·stable order·cleanup을 생략한다. 동결 경계: row-update lock 한 종류만 다룬다.
착각 방지
`원문 121–132줄`이 항목 전체 또는 외부 운영 Green을 단독 증명한다고 읽지 않는다.
하지 않는 일
이 chunk가 책임지지 않는 범위: row-update lock 한 종류만 다룬다.
다음 연결
다음 source chunk의 입력 또는 exact local marker·SQL oracle·사람 검토 경계로 결과를 넘긴다.
F07-C12 · 원문 133–144줄
문법 해부
133~144줄의 `원문 133–144줄`을 입력·grain/guard·관찰·cleanup/stable output 단계로 나눈다.
실제 값 추적
항목 전체 흐름에 연결해 `observed=1`을 대조한다. 이 값이 chunk 단독 산출이라는 뜻은 아니다.
정상 예
정상 예에서는 source 순서와 owner 계약이 일치해 `observed=1`을 관찰한다.
틀린 예·반례
반례에서는 선행 guard·grain·stable order·cleanup을 생략한다. 동결 경계: 외부 dashboard나 pool metric을 증명하지 않는다.
착각 방지
`원문 133–144줄`이 항목 전체 또는 외부 운영 Green을 단독 증명한다고 읽지 않는다.
하지 않는 일
이 chunk가 책임지지 않는 범위: 외부 dashboard나 pool metric을 증명하지 않는다.
다음 연결
다음 source chunk의 입력 또는 exact local marker·SQL oracle·사람 검토 경계로 결과를 넘긴다.
F07-C13 · 원문 145–156줄
문법 해부
145~156줄의 `원문 145–156줄`을 입력·grain/guard·관찰·cleanup/stable output 단계로 나눈다.
실제 값 추적
항목 전체 흐름에 연결해 `cleared=0`을 대조한다. 이 값이 chunk 단독 산출이라는 뜻은 아니다.
정상 예
정상 예에서는 source 순서와 owner 계약이 일치해 `cleared=0`을 관찰한다.
틀린 예·반례
반례에서는 선행 guard·grain·stable order·cleanup을 생략한다. 동결 경계: 실제 운영 DB를 관찰하지 않는다.
착각 방지
`원문 145–156줄`이 항목 전체 또는 외부 운영 Green을 단독 증명한다고 읽지 않는다.
하지 않는 일
이 chunk가 책임지지 않는 범위: 실제 운영 DB를 관찰하지 않는다.
다음 연결
다음 source chunk의 입력 또는 exact local marker·SQL oracle·사람 검토 경계로 결과를 넘긴다.
F07-C14 · 원문 157–168줄
문법 해부
157~168줄의 `원문 157–168줄`을 입력·grain/guard·관찰·cleanup/stable output 단계로 나눈다.
실제 값 추적
항목 전체 흐름에 연결해 `final_value=2`을 대조한다. 이 값이 chunk 단독 산출이라는 뜻은 아니다.
정상 예
정상 예에서는 source 순서와 owner 계약이 일치해 `final_value=2`을 관찰한다.
틀린 예·반례
반례에서는 선행 guard·grain·stable order·cleanup을 생략한다. 동결 경계: Compose/Container와 Docker·PostgreSQL이 필요하다.
착각 방지
`원문 157–168줄`이 항목 전체 또는 외부 운영 Green을 단독 증명한다고 읽지 않는다.
하지 않는 일
이 chunk가 책임지지 않는 범위: Compose/Container와 Docker·PostgreSQL이 필요하다.
다음 연결
다음 source chunk의 입력 또는 exact local marker·SQL oracle·사람 검토 경계로 결과를 넘긴다.
F07-C15 · 원문 169–180줄
문법 해부
169~180줄의 `원문 169–180줄`을 입력·grain/guard·관찰·cleanup/stable output 단계로 나눈다.
실제 값 추적
항목 전체 흐름에 연결해 `native_exits=0 cleanup=1`을 대조한다. 이 값이 chunk 단독 산출이라는 뜻은 아니다.
정상 예
정상 예에서는 source 순서와 owner 계약이 일치해 `native_exits=0 cleanup=1`을 관찰한다.
틀린 예·반례
반례에서는 선행 guard·grain·stable order·cleanup을 생략한다. 동결 경계: row-update lock 한 종류만 다룬다.
착각 방지
`원문 169–180줄`이 항목 전체 또는 외부 운영 Green을 단독 증명한다고 읽지 않는다.
하지 않는 일
이 chunk가 책임지지 않는 범위: row-update lock 한 종류만 다룬다.
다음 연결
다음 source chunk의 입력 또는 exact local marker·SQL oracle·사람 검토 경계로 결과를 넘긴다.
F07-C16 · 원문 181–189줄
문법 해부
181~189줄의 `원문 181–189줄`을 입력·grain/guard·관찰·cleanup/stable output 단계로 나눈다.
실제 값 추적
항목 전체 흐름에 연결해 `scope=ROW_UPDATE`을 대조한다. 이 값이 chunk 단독 산출이라는 뜻은 아니다.
정상 예
정상 예에서는 source 순서와 owner 계약이 일치해 `scope=ROW_UPDATE`을 관찰한다.
틀린 예·반례
반례에서는 선행 guard·grain·stable order·cleanup을 생략한다. 동결 경계: 외부 dashboard나 pool metric을 증명하지 않는다.
착각 방지
`원문 181–189줄`이 항목 전체 또는 외부 운영 Green을 단독 증명한다고 읽지 않는다.
하지 않는 일
이 chunk가 책임지지 않는 범위: 외부 dashboard나 pool metric을 증명하지 않는다.
다음 연결
다음 source chunk의 입력 또는 exact local marker·SQL oracle·사람 검토 경계로 결과를 넘긴다.
반례히토리 → 니지카 → 료 → 키타
  1. 히토리

    겉보기에는 맞지만 깨지는 예는?

  2. 니지카

    p766의 ACCESS EXCLUSIVE/SELECT 설명을 canonical UPDATE/UPDATE ROW_UPDATE보다 우선한다

  3. 그 상태는 입력 grain·owner·관찰 중 한 칸이 비어 있어.

  4. 키타

    수정한 뒤 같은 source bytes와 evidence를 다시 대조해.

08

STEP 08 / 13

실제 값 따라가기

같은 입력값이 어느 줄을 지나 어떤 결과가 되는지 추적합니다.

순서들어온 값코드가 하는 일나온 값·상태경계
F07-T01 observesame row two UPDATEpg_stat_activityobserved=1실제 lock snapshot 필요
F07-T02 releaseholder commitboth processes exitcleared=0, final=2timeout이면 실패
F07-T03 closeschema/Compose/tempfinally cleanupcleanup=1운영 DB p95 미보장
책임 경계히토리 → 니지카 → 료 → 키타
  1. 히토리

    이 항목의 마지막 책임선은?

  2. 니지카

    직접 역할은 `정본 PostgreSQL row-lock wait evidence producer`이야.

  3. 대표 경계는 `외부 dashboard나 pool metric을 증명하지 않는다`이야.

  4. 키타

    정본/학습용 label과 local/external owner까지 확인하면 끝이야.

09

STEP 09 / 13

Micrometer·RequestId·PowerShell·PostgreSQL 내부에서 벌어지는 일

Micrometer·JUnit·PowerShell·PostgreSQL·alert/runbook에서 실제로 일어나는 일과 증명 범위를 구분합니다.

PostgreSQL row lock

첫 UPDATE가 commit 전 같은 row의 둘째 UPDATE를 기다리게 한다.

p766의 stale ACCESS EXCLUSIVE/SELECT 설명이나 table lock·pool wait 전체를 대표하지 않는다.
native process

두 psql process의 exit code와 stderr를 직접 회수한다.

PowerShell cmdlet 성공만으로 native 성공이 아니다.
owner lifecycle

Compose ownership에 따라 down 여부를 결정한다.

Container mode의 caller resource를 지우지 않는다.
10

STEP 10 / 13

흔한 착각과 틀린 예

그럴듯하지만 틀린 해석을 반례로 고칩니다.

❌ p766의 ACCESS EXCLUSIVE/SELECT 설명을 canonical UPDATE/UPDATE ROW_UPDATE보다 우선한다

왜 틀리나 정본 PostgreSQL row-lock wait evidence producer의 grain·owner·관찰·경계 중 적어도 하나를 건너뛴다.

바르게 읽기 disposable schema와 value=0 fixture를 만든다. 그리고 source의 실제 값과 provenance를 다시 대조한다.

반례 반례에서는 `실제 운영 DB를 관찰하지 않는다` 상태인데도 Green을 주장하게 된다.

❌ sleep만 보고 lock wait를 관찰했다고 한다

왜 틀리나 정본 PostgreSQL row-lock wait evidence producer의 grain·owner·관찰·경계 중 적어도 하나를 건너뛴다.

바르게 읽기 holder와 waiter UPDATE를 별도 process로 시작한다. 그리고 source의 실제 값과 provenance를 다시 대조한다.

반례 반례에서는 `Compose/Container와 Docker·PostgreSQL이 필요하다` 상태인데도 Green을 주장하게 된다.

❌ final_value=2만 보고 대기 해제를 생략한다

왜 틀리나 정본 PostgreSQL row-lock wait evidence producer의 grain·owner·관찰·경계 중 적어도 하나를 건너뛴다.

바르게 읽기 Lock wait와 blocking pid를 관찰한다. 그리고 source의 실제 값과 provenance를 다시 대조한다.

반례 반례에서는 `row-update lock 한 종류만 다룬다` 상태인데도 Green을 주장하게 된다.

❌ 실패 때 cleanup 검사를 건너뛴다

왜 틀리나 정본 PostgreSQL row-lock wait evidence producer의 grain·owner·관찰·경계 중 적어도 하나를 건너뛴다.

바르게 읽기 wait=0·value=2·native exit=0·cleanup=1 뒤 evidence를 발행한다. 그리고 source의 실제 값과 provenance를 다시 대조한다.

반례 반례에서는 `외부 dashboard나 pool metric을 증명하지 않는다` 상태인데도 Green을 주장하게 된다.

❌ 격리 drill을 운영 DB 성능 증거로 부른다

왜 틀리나 정본 PostgreSQL row-lock wait evidence producer의 grain·owner·관찰·경계 중 적어도 하나를 건너뛴다.

바르게 읽기 wait=0·value=2·native exit=0·cleanup=1 뒤 evidence를 발행한다. 그리고 source의 실제 값과 provenance를 다시 대조한다.

반례 반례에서는 `실제 운영 DB를 관찰하지 않는다` 상태인데도 Green을 주장하게 된다.

11

STEP 11 / 13

이 코드가 보장하지 않는 것

이 코드가 책임지지 않는 일을 분리합니다.

직접 미보장

실제 운영 DB를 관찰하지 않는다

이 책임을 맡는 곳: metric/query grain
직접 미보장

Compose/Container와 Docker·PostgreSQL이 필요하다

이 책임을 맡는 곳: 별도 local/external 실행
직접 미보장

row-update lock 한 종류만 다룬다

이 책임을 맡는 곳: secret·개인정보·운영 정책
직접 미보장

외부 dashboard나 pool metric을 증명하지 않는다

이 책임을 맡는 곳: infrastructure·사람 검토
12

STEP 12 / 13

직접 다시 써보기

뜻 → 조각 → 전체 코드 순서로 다시 씁니다.

1단계 · 뜻부터 복원

다음 역할을 고정값과 미보장 경계까지 말한다: disposable PostgreSQL row lock wait를 만들고 관찰·해소·최종값·native exit·cleanup을 검증해 db-wait.json을 원자 발행하는 제공 정본 runner다.

2단계 · 코드 조각 재조립

  1. 원문 1–12줄
  2. 원문 13–24줄
  3. 원문 25–36줄
  4. 원문 37–48줄
  5. 원문 49–60줄
  6. 원문 61–72줄
  7. 원문 73–84줄
  8. 원문 85–96줄
  9. 원문 97–108줄
  10. 원문 109–120줄
  11. 원문 121–132줄
  12. 원문 133–144줄
  13. 원문 145–156줄
  14. 원문 157–168줄
  15. 원문 169–180줄
  16. 원문 181–189줄

3단계 · 파일 전체 다시 쓰기

189개 물리 줄을 원본 순서로 복원하고 SHA-256 94f195680c8a23b549bd8a4b650b63df7811ef58965ba2edce8f29691620cb81와 대조한다.

자가 점검
  • 원본 source/template bytes와 줄 번호를 바꾸지 않았는가?
  • 정본 3개와 학습용 예시 8개를 구분했는가?
  • RequestId local Gate와 DB wait local drill의 Green 범위를 분리했는가?
  • dashboard·alert·incident timeline을 NOT_RUN_EXTERNAL 또는 사람 검토로 남겼는가?
  • Q37의 JOIN grain과 Q38의 SUCCESS·반개구간 가정을 드러냈는가?
13

STEP 13 / 13

전체 원본 source

감사로 고정한 전체 source를 가감 없이 확인합니다.

원문 정본 전체 source 확인하기
원문 정본 · 완전한 packaged PowerShell sourcescripts/run-w23-db-wait.ps1SHA-256 94f195680c8a23b549bd8a4b650b63df7811ef58965ba2edce8f29691620cb81
run-w23-db-wait.ps1 — 실제 row-lock wait 1→0과 final value 2를 증명하는 정본 drill 전체
param(
    [ValidateSet('Compose','Container')][string]$Mode = 'Compose',
    [string]$ComposeProject = 'w23-db-wait-lab',
    [string]$Container = '',
    [Parameter(Mandatory = $true)][string]$EvidencePath
)

Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'

$root = Split-Path -Parent $PSScriptRoot
$evidence = if ([IO.Path]::IsPathRooted($EvidencePath)) {
    [IO.Path]::GetFullPath($EvidencePath)
} else {
    [IO.Path]::GetFullPath((Join-Path $root $EvidencePath))
}
$compose = Join-Path $root 'compose.yaml'
$runId = [guid]::NewGuid().ToString('N').Substring(0, 12)
$holderApp = "w23_holder_$runId"
$waiterApp = "w23_waiter_$runId"
$holderSqlInContainer = "/tmp/w23-holder-$runId.sql"
$waiterSqlInContainer = "/tmp/w23-waiter-$runId.sql"
$holderSqlLocal = Join-Path $env:TEMP "w23-holder-$runId.sql"
$waiterSqlLocal = Join-Path $env:TEMP "w23-waiter-$runId.sql"
$holderOut = Join-Path $env:TEMP "w23-holder-$runId.out"
$holderErr = Join-Path $env:TEMP "w23-holder-$runId.err"
$waiterOut = Join-Path $env:TEMP "w23-waiter-$runId.out"
$waiterErr = Join-Path $env:TEMP "w23-waiter-$runId.err"
$owned = $false
$fixtureCreated = $false
$cleanup = $false
$holderProcess = $null
$waiterProcess = $null
$failure = $null
$body = $null

function Invoke-PsqlScalar([string]$Sql) {
    $previousPreference = $ErrorActionPreference
    $ErrorActionPreference = 'Continue'
    try {
        $rows = @(& docker exec $Container psql -X -q -A -t -v ON_ERROR_STOP=1 -U app -d financial_core -c $Sql 2>&1)
        $nativeExit = $LASTEXITCODE
    } finally {
        $ErrorActionPreference = $previousPreference
    }
    if ($nativeExit -ne 0) { throw "W23 psql failed: $($rows -join "`n")" }
    $values = @($rows | ForEach-Object { ([string]$_).Trim() } | Where-Object { $_ })
    if ($values.Count -lt 1) { throw 'W23 psql returned no scalar value' }
    return $values[-1]
}

try {
    if ($Mode -ceq 'Compose') {
        if ($Container) { throw 'W23 Compose mode rejects Container' }
        if ([string]::IsNullOrWhiteSpace($env:FCL_DB_PASSWORD)) {
            $env:FCL_DB_PASSWORD = 'w23-disposable-password'
        }
        # Mark ownership before startup so partial Compose creation is always
        # torn down in finally, even when `up --wait` itself fails.
        $owned = $true
        & docker compose -f $compose -p $ComposeProject up -d --wait db
        if ($LASTEXITCODE -ne 0) { throw "W23 compose up exit=$LASTEXITCODE" }
        $Container = (& docker compose -f $compose -p $ComposeProject ps -q db).Trim()
    } elseif ([string]::IsNullOrWhiteSpace($Container)) {
        throw 'W23 Container mode requires Container'
    }
    if ([string]::IsNullOrWhiteSpace($Container)) { throw 'W23 container resolution failed' }

    $setup = "DROP SCHEMA IF EXISTS w23_wait CASCADE; CREATE SCHEMA w23_wait; CREATE TABLE w23_wait.probe(id int PRIMARY KEY,value int NOT NULL); INSERT INTO w23_wait.probe VALUES(1,0);"
    Invoke-PsqlScalar("$setup SELECT count(*) FROM w23_wait.probe;") | Out-Null
    $fixtureCreated = $true

    @"
\set ON_ERROR_STOP on
SET application_name='$holderApp';
BEGIN;
UPDATE w23_wait.probe SET value=value+1 WHERE id=1;
SELECT pg_sleep(6);
COMMIT;
"@ | Set-Content -Encoding utf8 -LiteralPath $holderSqlLocal
    @"
\set ON_ERROR_STOP on
SET application_name='$waiterApp';
SET lock_timeout='10s';
UPDATE w23_wait.probe SET value=value+1 WHERE id=1;
"@ | Set-Content -Encoding utf8 -LiteralPath $waiterSqlLocal

    & docker cp $holderSqlLocal "${Container}:$holderSqlInContainer" | Out-Null
    if ($LASTEXITCODE -ne 0) { throw 'W23 holder SQL copy failed' }
    & docker cp $waiterSqlLocal "${Container}:$waiterSqlInContainer" | Out-Null
    if ($LASTEXITCODE -ne 0) { throw 'W23 waiter SQL copy failed' }

    $holderProcess = Start-Process docker -ArgumentList @(
        'exec',$Container,'psql','-X','-v','ON_ERROR_STOP=1','-U','app','-d','financial_core','-f',$holderSqlInContainer
    ) -RedirectStandardOutput $holderOut -RedirectStandardError $holderErr -PassThru -WindowStyle Hidden
    Start-Sleep -Seconds 1
    $waiterProcess = Start-Process docker -ArgumentList @(
        'exec',$Container,'psql','-X','-v','ON_ERROR_STOP=1','-U','app','-d','financial_core','-f',$waiterSqlInContainer
    ) -RedirectStandardOutput $waiterOut -RedirectStandardError $waiterErr -PassThru -WindowStyle Hidden
    Start-Sleep -Seconds 1

    $snapshotRaw = Invoke-PsqlScalar(
        "SELECT wait_event_type||'|'||coalesce(wait_event,'')||'|'||cardinality(pg_blocking_pids(pid)) FROM pg_stat_activity WHERE application_name='$waiterApp' AND wait_event_type='Lock';"
    )
    $snapshot = $snapshotRaw.Split('|')
    if ($snapshot.Count -ne 3 -or $snapshot[0] -cne 'Lock' -or [int]$snapshot[2] -lt 1) {
        throw "W23 exact row-lock snapshot invalid: $snapshotRaw"
    }
    $observed = 1

    if (!$holderProcess.WaitForExit(15000) -or !$waiterProcess.WaitForExit(15000)) {
        throw 'W23 native process timeout'
    }
    $holderProcess.WaitForExit(); $waiterProcess.WaitForExit()
    $holderProcess.Refresh(); $waiterProcess.Refresh()
    $holderExit = [int]$holderProcess.ExitCode
    $waiterExit = [int]$waiterProcess.ExitCode
    if ($holderExit -ne 0 -or $waiterExit -ne 0) {
        $errors = @(
            if (Test-Path $holderErr) { Get-Content -Raw $holderErr }
            if (Test-Path $waiterErr) { Get-Content -Raw $waiterErr }
        ) -join "`n"
        throw "W23 native process failure holder=$holderExit waiter=$waiterExit`n$errors"
    }
    $cleared = [int](Invoke-PsqlScalar("SELECT count(*) FROM pg_stat_activity WHERE application_name IN ('$holderApp','$waiterApp') AND wait_event_type='Lock';"))
    $finalValue = [int](Invoke-PsqlScalar('SELECT value FROM w23_wait.probe WHERE id=1;'))
    if ($cleared -ne 0 -or $finalValue -ne 2) {
        throw "W23 wait/final value mismatch cleared=$cleared value=$finalValue"
    }

    $body = [ordered]@{
        run_id = $runId
        holder_session = $holderApp
        waiter_session = $waiterApp
        fixture = 'w23_wait.probe(id=1,value=0)'
        lock_scope = 'ROW_UPDATE'
        observed = $observed
        cleared = $cleared
        holder_exit = $holderExit
        waiter_exit = $waiterExit
        native_exits = 0
        final_value = $finalValue
        snapshot = [ordered]@{
            wait_event_type = $snapshot[0]
            wait_event = $snapshot[1]
            blocking_session_count = [int]$snapshot[2]
            query_redacted = 'UPDATE w23_wait.probe WHERE id=?'
        }
        source_sha256 = (Get-FileHash -LiteralPath $MyInvocation.MyCommand.Path -Algorithm SHA256).Hash.ToLowerInvariant()
    }
} catch {
    $failure = $_
} finally {
    foreach ($process in @($holderProcess,$waiterProcess)) {
        if ($null -ne $process -and !$process.HasExited) {
            Stop-Process -Id $process.Id -Force -ErrorAction SilentlyContinue
        }
    }
    $schemaCleanup = $true
    if ($fixtureCreated -and ![string]::IsNullOrWhiteSpace($Container)) {
        & docker exec $Container psql -X -q -v ON_ERROR_STOP=1 -U app -d financial_core -c 'DROP SCHEMA IF EXISTS w23_wait CASCADE;' | Out-Null
        $schemaCleanup = ($LASTEXITCODE -eq 0)
        & docker exec $Container rm -f $holderSqlInContainer $waiterSqlInContainer | Out-Null
    }
    $composeCleanup = $true
    if ($owned) {
        & docker compose -f $compose -p $ComposeProject down -v --remove-orphans | Out-Null
        $composeCleanup = ($LASTEXITCODE -eq 0)
    }
    $cleanup = $schemaCleanup -and $composeCleanup
    Remove-Item $holderSqlLocal,$waiterSqlLocal,$holderOut,$holderErr,$waiterOut,$waiterErr -Force -ErrorAction SilentlyContinue
}

if (!$cleanup) {
    if ($null -ne $failure) {
        throw "W23 DB wait failed and cleanup was not confirmed: $($failure.Exception.Message)"
    }
    throw 'W23 DB wait cleanup was not confirmed'
}
if ($null -ne $failure) { throw $failure }
if ($null -eq $body) { throw 'W23 DB wait produced no result' }

$body['cleanup'] = 1
New-Item -ItemType Directory -Force (Split-Path -Parent $evidence) | Out-Null
$temporary = "$evidence.tmp"
$body | ConvertTo-Json -Depth 6 | Set-Content -Encoding utf8 -LiteralPath $temporary
Move-Item -LiteralPath $temporary -Destination $evidence -Force

"W23_DB_WAIT_GREEN scope=ROW_UPDATE observed=1 cleared=0 final_value=2 native_exits=0 cleanup=1"
08

D5 alerts — 5xx·p95·ledger mismatch 세 경보의 조건과 사람 대응

illustrative/markdown/W23-D5-alerts.md

학습용 예시 · alert/runbook template · 정본 답안 아님 · 외부 미실행 · 학습용 예시 · 정본 답안 아님 · W23-F08
9줄 연결9줄 번역2 chunks
01

STEP 01 / 13

오늘 이 코드에서 해결할 문제

무엇을 이해해야 하는지 질문부터 잡습니다.

오늘의 한 문장

High5xx·SlowTransfer·LedgerMismatch 세 알림의 조건·window·severity·owner·action·runbook·clear를 적는 학습 template이다.

  1. `alerts=3`은 어느 줄에서 생기거나 검증될까?
  2. 입력→guard→관찰→cleanup 또는 stable output 순서는 무엇인가?
  3. local 자동 owner와 external human owner는 각각 누구인가?
  4. 이 source가 직접 관찰하지 않은 Green은 무엇인가?
  5. 반례는 `notification URL·시각·screenshot hash 없이는 외부 실행이 아니다` 경계와 어떻게 연결되는가?
이 파일에서 끝까지 다시 쓰는 값alerts=35xx_rate>2%p95>1000msmismatch_count>0NOT_RUN_EXTERNAL
02

STEP 02 / 13

아주 짧게: 이 코드는 왜 필요할까?

웹소설 대신 이 코드가 필요한 이유만 두 문단으로 쉽게 봅니다.

STARRY가 metric catalog·requestId 봉투·DB wait 영수증·alert/runbook·SQL grain 표를 서로 다른 칸에 놓는다.

D5 alerts — 5xx·p95·ledger mismatch 세 경보의 조건과 사람 대응 ― 관측 증거 흐름으로 바꾸기

High5xx·SlowTransfer·LedgerMismatch 세 알림의 조건·window·severity·owner·action·runbook·clear를 적는 학습 template이다.

핵심값 alerts=3, 5xx_rate>2%, p95>1000ms, mismatch_count>0, NOT_RUN_EXTERNAL을 원본 줄로 따라가되, `notification URL·시각·screenshot hash 없이는 외부 실행이 아니다`까지 함께 표시해 local 관찰을 외부 운영 Green으로 부풀리지 않는다.

딱 여기까지만 비유는 grain·owner·순서를 기억하게 할 뿐 실제 Gradle/Docker/PostgreSQL 실행, dashboard·notification, 운영 SLA를 자동 증명하지 않는다.

03

STEP 03 / 13

초등학생도 이해하는 설명

생활 비유와 실제 코드의 경계를 함께 확인합니다.

원문 1–10줄

1~10줄을 한 덩어리로 읽어 1번째 움직임을 본다. High5xx·SlowTransfer·LedgerMismatch 세 알림의 조건·window·severity·owner·action·runbook·clear를 적는 학습 template이다.

코드 연결
1~10줄
비유
화재·느림·원장 불일치 세 경보마다 울리는 조건, 기다릴 시간, 담당자, 첫 행동, 해제 조건을 한 줄씩 붙인 비상벨 표
비유의 끝
notification URL·시각·screenshot hash 없이는 외부 실행이 아니다

원문 11–11줄

11~11줄을 한 덩어리로 읽어 2번째 움직임을 본다. High5xx·SlowTransfer·LedgerMismatch 세 알림의 조건·window·severity·owner·action·runbook·clear를 적는 학습 template이다.

코드 연결
11~11줄
비유
화재·느림·원장 불일치 세 경보마다 울리는 조건, 기다릴 시간, 담당자, 첫 행동, 해제 조건을 한 줄씩 붙인 비상벨 표
비유의 끝
학습 threshold는 운영 SLA가 아니다
문제의 첫 장면히토리 → 니지카 → 료 → 키타
  1. 히토리

    첫 고정값은 `alerts=3` 맞아?

  2. 니지카

    High5xx·SlowTransfer·LedgerMismatch 세 알림의 조건·window·severity·owner·action·runbook·clear를 적는 학습 template이다.

  3. 원문에서 `alerts=3`이 만들어지거나 확인되는 줄을 찾자.

  4. 키타

    그리고 `notification URL·시각·screenshot hash 없이는 외부 실행이 아니다`도 같이 적어.

입력에서 결과까지히토리 → 니지카 → 료 → 키타
  1. 히토리

    `5xx_rate>2%`은 언제 생겨?

  2. 니지카

    5xx rate와 업무 409를 분리한다. → p95와 pool/DB wait를 함께 진단한다.

  3. mismatch>0이면 재처리를 멈춘다. → clear 조건과 외부 evidence를 사람이 확인한다.

  4. 키타

    관찰값과 `학습 threshold는 운영 SLA가 아니다`을 분리하면 돼.

04

STEP 04 / 13

비유 ↔ 코드 전체 연결표

감사 규칙상 연결 대상인 원본 9줄을 빠짐없이 연결합니다.

단어 몇 개만 뽑은 표가 아닙니다.학습용 예시 · alert/runbook template · 정본 답안 아님 · 외부 미실행에서 비어 있지 않은 모든 줄을 원본 줄 번호 그대로 연결했습니다.9 / 9 연결
정확한 원본 줄STARRY 비유실제 뜻·입력·결과·한계
1줄F08-L01 # W23 alert 3종 학습용 예시 - 사람 검토 전 Green 아님 화재·느림·원장 불일치 세 경보마다 울리는 조건, 기다릴 시간, 담당자, 첫 행동, 해제 조건을 한 줄씩 붙인 비상벨 표 이 source의 provenance·grain·가정·반례·실행 경계를 사람이 확인할 설명 줄이다.
입력
5xx rate·p95·mismatch metric과 owner/runbook/clear 기준
결과·효과
이 줄 뒤에는 항목 전체의 `alerts=3` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
notification URL·시각·screenshot hash 없이는 외부 실행이 아니다
3줄F08-L03 | 이름 | 조건 | window | severity | owner | first query/action | runbook | clear | 화재·느림·원장 불일치 세 경보마다 울리는 조건, 기다릴 시간, 담당자, 첫 행동, 해제 조건을 한 줄씩 붙인 비상벨 표 비정본 alert 조건·owner·clear 학습 template의 3번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
입력
5xx rate·p95·mismatch metric과 owner/runbook/clear 기준
결과·효과
이 줄 뒤에는 항목 전체의 `p95>1000ms` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
업무 409를 5xx에 합산하지 않는다
4줄F08-L04 |---|---|---|---|---|---|---|---| 화재·느림·원장 불일치 세 경보마다 울리는 조건, 기다릴 시간, 담당자, 첫 행동, 해제 조건을 한 줄씩 붙인 비상벨 표 비정본 alert 조건·owner·clear 학습 template의 4번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
입력
5xx rate·p95·mismatch metric과 owner/runbook/clear 기준
결과·효과
이 줄 뒤에는 항목 전체의 `mismatch_count>0` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
문서 작성만으로 alert delivery가 증명되지 않는다
5줄F08-L05 | High5xx | 5xx_rate > 2% | 5분 지속 | SEV2 | API on-call | requestId sample과 route/status 확인 | runbooks/db-timeout.md | 10분간 1% 미만 | 화재·느림·원장 불일치 세 경보마다 울리는 조건, 기다릴 시간, 담당자, 첫 행동, 해제 조건을 한 줄씩 붙인 비상벨 표 업무 거절을 제외한 5xx 비율의 지속 조건·owner·clear 계약을 한 행에 묶는다.
입력
5xx rate·p95·mismatch metric과 owner/runbook/clear 기준
결과·효과
이 줄 뒤에는 항목 전체의 `NOT_RUN_EXTERNAL` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
notification URL·시각·screenshot hash 없이는 외부 실행이 아니다
6줄F08-L06 | SlowTransfer | p95 > 1000ms | 10분 지속 | SEV2 | transfer on-call | pool pending과 DB lock wait를 분리 확인 | runbooks/db-timeout.md | 10분간 p95 < 500ms | 화재·느림·원장 불일치 세 경보마다 울리는 조건, 기다릴 시간, 담당자, 첫 행동, 해제 조건을 한 줄씩 붙인 비상벨 표 p95 지연과 pool pending·DB wait 분리 진단을 연결하는 학습 alert다.
입력
5xx rate·p95·mismatch metric과 owner/runbook/clear 기준
결과·효과
이 줄 뒤에는 항목 전체의 `alerts=3` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
학습 threshold는 운영 SLA가 아니다
7줄F08-L07 | LedgerMismatch | mismatch_count > 0 | 대사 1회 | SEV1 | finance ops | 재처리 중지, 영향 계좌 격리, source 대조 | runbooks/ledger-mismatch.md | 승인된 correction 뒤 mismatch 0 | 화재·느림·원장 불일치 세 경보마다 울리는 조건, 기다릴 시간, 담당자, 첫 행동, 해제 조건을 한 줄씩 붙인 비상벨 표 불일치가 하나라도 있으면 재처리를 멈추고 finance 승인을 요구하는 alert다.
입력
5xx rate·p95·mismatch metric과 owner/runbook/clear 기준
결과·효과
이 줄 뒤에는 항목 전체의 `5xx_rate>2%` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
업무 409를 5xx에 합산하지 않는다
9줄F08-L09 - 업무 409 거절은 5xx 장애율에 합산하지 않는다. 화재·느림·원장 불일치 세 경보마다 울리는 조건, 기다릴 시간, 담당자, 첫 행동, 해제 조건을 한 줄씩 붙인 비상벨 표 비정본 alert 조건·owner·clear 학습 template의 9번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
입력
5xx rate·p95·mismatch metric과 owner/runbook/clear 기준
결과·효과
이 줄 뒤에는 항목 전체의 `mismatch_count>0` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
notification URL·시각·screenshot hash 없이는 외부 실행이 아니다
10줄F08-L10 - notification URL, 실행시각, screenshot SHA-256이 없으면 `NOT_RUN_EXTERNAL`이다. 화재·느림·원장 불일치 세 경보마다 울리는 조건, 기다릴 시간, 담당자, 첫 행동, 해제 조건을 한 줄씩 붙인 비상벨 표 URL·관찰시각·screenshot hash가 없어 외부 실행을 아직 주장하지 않는 정확한 상태다.
입력
5xx rate·p95·mismatch metric과 owner/runbook/clear 기준
결과·효과
이 줄 뒤에는 항목 전체의 `NOT_RUN_EXTERNAL` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
학습 threshold는 운영 SLA가 아니다
11줄F08-L11 - threshold는 학습 baseline이며 운영 SLA라고 주장하지 않는다. 화재·느림·원장 불일치 세 경보마다 울리는 조건, 기다릴 시간, 담당자, 첫 행동, 해제 조건을 한 줄씩 붙인 비상벨 표 비정본 alert 조건·owner·clear 학습 template의 11번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
입력
5xx rate·p95·mismatch metric과 owner/runbook/clear 기준
결과·효과
이 줄 뒤에는 항목 전체의 `alerts=3` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
업무 409를 5xx에 합산하지 않는다
Green 범위히토리 → 니지카 → 료 → 키타
  1. 히토리

    marker나 문서가 보이면 W23 전체 성공이야?

  2. 니지카

    아니. 이 source가 직접 검증한 claim만 말해야 해.

  3. 직접 연결되는 대표 값은 `NOT_RUN_EXTERNAL`이야.

  4. 키타

    `업무 409를 5xx에 합산하지 않는다`는 별도 실행·사람 증거가 필요해.

05

STEP 05 / 13

원본 코드 조각

원본을 2개 의미 조각으로 나누어 그대로 확인합니다.

파일을 한꺼번에 외우지 않고 실행 의미가 이어지는 작은 조각으로 봅니다. 아래 코드는 prompt·fixture·가정을 밝힌 학습용 예시 source이며, 제공 정본 답안이 아닙니다.

F08-C01 · 원문 1–10줄1–10줄
1–10줄 원본
# W23 alert 3종 학습용 예시 - 사람 검토 전 Green 아님

| 이름 | 조건 | window | severity | owner | first query/action | runbook | clear |
|---|---|---|---|---|---|---|---|
| High5xx | 5xx_rate > 2% | 5분 지속 | SEV2 | API on-call | requestId sample과 route/status 확인 | runbooks/db-timeout.md | 10분간 1% 미만 |
| SlowTransfer | p95 > 1000ms | 10분 지속 | SEV2 | transfer on-call | pool pending과 DB lock wait를 분리 확인 | runbooks/db-timeout.md | 10분간 p95 < 500ms |
| LedgerMismatch | mismatch_count > 0 | 대사 1회 | SEV1 | finance ops | 재처리 중지, 영향 계좌 격리, source 대조 | runbooks/ledger-mismatch.md | 승인된 correction 뒤 mismatch 0 |

- 업무 409 거절은 5xx 장애율에 합산하지 않는다.
- notification URL, 실행시각, screenshot SHA-256이 없으면 `NOT_RUN_EXTERNAL`이다.
F08-C02 · 원문 11–11줄11–11줄
11–11줄 원본
- threshold는 학습 baseline이며 운영 SLA라고 주장하지 않는다.
06

STEP 06 / 13

코드 한 줄씩 한국어로 번역

비어 있지 않은 9줄을 모두 한국어로 옮깁니다.

전체 번역 9 / 9

비어 있지 않은 원본 줄은 하나도 생략하지 않습니다.

원본한국어 번역
1# W23 alert 3종 학습용 예시 - 사람 검토 전 Green 아님이 source의 provenance·grain·가정·반례·실행 경계를 사람이 확인할 설명 줄이다.
3| 이름 | 조건 | window | severity | owner | first query/action | runbook | clear |비정본 alert 조건·owner·clear 학습 template의 3번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
4|---|---|---|---|---|---|---|---|비정본 alert 조건·owner·clear 학습 template의 4번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
5| High5xx | 5xx_rate > 2% | 5분 지속 | SEV2 | API on-call | requestId sample과 route/status 확인 | runbooks/db-timeout.md | 10분간 1% 미만 |업무 거절을 제외한 5xx 비율의 지속 조건·owner·clear 계약을 한 행에 묶는다.
6| SlowTransfer | p95 > 1000ms | 10분 지속 | SEV2 | transfer on-call | pool pending과 DB lock wait를 분리 확인 | runbooks/db-timeout.md | 10분간 p95 < 500ms |p95 지연과 pool pending·DB wait 분리 진단을 연결하는 학습 alert다.
7| LedgerMismatch | mismatch_count > 0 | 대사 1회 | SEV1 | finance ops | 재처리 중지, 영향 계좌 격리, source 대조 | runbooks/ledger-mismatch.md | 승인된 correction 뒤 mismatch 0 |불일치가 하나라도 있으면 재처리를 멈추고 finance 승인을 요구하는 alert다.
9- 업무 409 거절은 5xx 장애율에 합산하지 않는다.비정본 alert 조건·owner·clear 학습 template의 9번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
10- notification URL, 실행시각, screenshot SHA-256이 없으면 `NOT_RUN_EXTERNAL`이다.URL·관찰시각·screenshot hash가 없어 외부 실행을 아직 주장하지 않는 정확한 상태다.
11- threshold는 학습 baseline이며 운영 SLA라고 주장하지 않는다.비정본 alert 조건·owner·clear 학습 template의 11번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
07

STEP 07 / 13

기존 수준의 한 줄 읽기·문법 해부

쉬운 설명 다음에 문법과 실행 순서를 정밀하게 읽습니다.

한 줄로 읽기

High5xx·SlowTransfer·LedgerMismatch 세 알림의 조건·window·severity·owner·action·runbook·clear를 적는 학습 template이다. 다만 notification URL·시각·screenshot hash 없이는 외부 실행이 아니다

문법 해부

  • Markdown 표의 한 행이 condition·window·severity·owner·action·runbook·clear를 한 alert 계약으로 묶는다.
  • notification URL·observed_at·screenshot hash가 없으면 표를 작성해도 `NOT_RUN_EXTERNAL`이다.

실행 순서

  1. 5xx rate와 업무 409를 분리한다.
  2. p95와 pool/DB wait를 함께 진단한다.
  3. mismatch>0이면 재처리를 멈춘다.
  4. clear 조건과 외부 evidence를 사람이 확인한다.

W23 조각별 정밀 해설

F08-C01 · 원문 1–10줄
문법 해부
1~10줄의 `원문 1–10줄`을 입력·grain/guard·관찰·cleanup/stable output 단계로 나눈다.
실제 값 추적
항목 전체 흐름에 연결해 `alerts=3`을 대조한다. 이 값이 chunk 단독 산출이라는 뜻은 아니다.
정상 예
정상 예에서는 source 순서와 owner 계약이 일치해 `alerts=3`을 관찰한다.
틀린 예·반례
반례에서는 선행 guard·grain·stable order·cleanup을 생략한다. 동결 경계: notification URL·시각·screenshot hash 없이는 외부 실행이 아니다.
착각 방지
`원문 1–10줄`이 항목 전체 또는 외부 운영 Green을 단독 증명한다고 읽지 않는다.
하지 않는 일
이 chunk가 책임지지 않는 범위: notification URL·시각·screenshot hash 없이는 외부 실행이 아니다.
다음 연결
다음 source chunk의 입력 또는 exact local marker·SQL oracle·사람 검토 경계로 결과를 넘긴다.
F08-C02 · 원문 11–11줄
문법 해부
11~11줄의 `원문 11–11줄`을 입력·grain/guard·관찰·cleanup/stable output 단계로 나눈다.
실제 값 추적
항목 전체 흐름에 연결해 `5xx_rate>2%`을 대조한다. 이 값이 chunk 단독 산출이라는 뜻은 아니다.
정상 예
정상 예에서는 source 순서와 owner 계약이 일치해 `5xx_rate>2%`을 관찰한다.
틀린 예·반례
반례에서는 선행 guard·grain·stable order·cleanup을 생략한다. 동결 경계: 학습 threshold는 운영 SLA가 아니다.
착각 방지
`원문 11–11줄`이 항목 전체 또는 외부 운영 Green을 단독 증명한다고 읽지 않는다.
하지 않는 일
이 chunk가 책임지지 않는 범위: 학습 threshold는 운영 SLA가 아니다.
다음 연결
다음 source chunk의 입력 또는 exact local marker·SQL oracle·사람 검토 경계로 결과를 넘긴다.
반례히토리 → 니지카 → 료 → 키타
  1. 히토리

    겉보기에는 맞지만 깨지는 예는?

  2. 니지카

    업무 409를 5xx 분자에 넣는다

  3. 그 상태는 입력 grain·owner·관찰 중 한 칸이 비어 있어.

  4. 키타

    수정한 뒤 같은 source bytes와 evidence를 다시 대조해.

08

STEP 08 / 13

실제 값 따라가기

같은 입력값이 어느 줄을 지나 어떤 결과가 되는지 추적합니다.

순서들어온 값코드가 하는 일나온 값·상태경계
F08-T01 High5xx5xx_rate >2%5분SEV2409 제외
F08-T02 SlowTransferp95 >1000ms10분SEV2pool과 DB wait 분리
F08-T03 LedgerMismatchcount >0one reconciliationSEV1승인 correction 필요
책임 경계히토리 → 니지카 → 료 → 키타
  1. 히토리

    이 항목의 마지막 책임선은?

  2. 니지카

    직접 역할은 `비정본 alert 조건·owner·clear 학습 template`이야.

  3. 대표 경계는 `문서 작성만으로 alert delivery가 증명되지 않는다`이야.

  4. 키타

    정본/학습용 label과 local/external owner까지 확인하면 끝이야.

09

STEP 09 / 13

Micrometer·RequestId·PowerShell·PostgreSQL 내부에서 벌어지는 일

Micrometer·JUnit·PowerShell·PostgreSQL·alert/runbook에서 실제로 일어나는 일과 증명 범위를 구분합니다.

query window

순간 spike가 아니라 지속 조건을 평가한다.

학습 threshold가 실제 SLA는 아니다.
notification

조건 충족 event를 on-call에게 전달한다.

URL·시각·screenshot이 없으면 미실행이다.
validator

필수 열·행 수·파일 hash 같은 shape를 검사할 수 있다.

threshold·owner·첫 행동의 운영 의미까지 자동 검증하지 않는다.
10

STEP 10 / 13

흔한 착각과 틀린 예

그럴듯하지만 틀린 해석을 반례로 고칩니다.

❌ 업무 409를 5xx 분자에 넣는다

왜 틀리나 비정본 alert 조건·owner·clear 학습 template의 grain·owner·관찰·경계 중 적어도 하나를 건너뛴다.

바르게 읽기 5xx rate와 업무 409를 분리한다. 그리고 source의 실제 값과 provenance를 다시 대조한다.

반례 반례에서는 `notification URL·시각·screenshot hash 없이는 외부 실행이 아니다` 상태인데도 Green을 주장하게 된다.

❌ p95 alert만 보고 DB lock이라고 단정한다

왜 틀리나 비정본 alert 조건·owner·clear 학습 template의 grain·owner·관찰·경계 중 적어도 하나를 건너뛴다.

바르게 읽기 p95와 pool/DB wait를 함께 진단한다. 그리고 source의 실제 값과 provenance를 다시 대조한다.

반례 반례에서는 `학습 threshold는 운영 SLA가 아니다` 상태인데도 Green을 주장하게 된다.

❌ mismatch 경보 뒤 자동 balance UPDATE를 한다

왜 틀리나 비정본 alert 조건·owner·clear 학습 template의 grain·owner·관찰·경계 중 적어도 하나를 건너뛴다.

바르게 읽기 mismatch>0이면 재처리를 멈춘다. 그리고 source의 실제 값과 provenance를 다시 대조한다.

반례 반례에서는 `업무 409를 5xx에 합산하지 않는다` 상태인데도 Green을 주장하게 된다.

❌ clear 조건 없이 alert를 닫는다

왜 틀리나 비정본 alert 조건·owner·clear 학습 template의 grain·owner·관찰·경계 중 적어도 하나를 건너뛴다.

바르게 읽기 clear 조건과 외부 evidence를 사람이 확인한다. 그리고 source의 실제 값과 provenance를 다시 대조한다.

반례 반례에서는 `문서 작성만으로 alert delivery가 증명되지 않는다` 상태인데도 Green을 주장하게 된다.

❌ template을 실제 notification Green이라 부른다

왜 틀리나 비정본 alert 조건·owner·clear 학습 template의 grain·owner·관찰·경계 중 적어도 하나를 건너뛴다.

바르게 읽기 clear 조건과 외부 evidence를 사람이 확인한다. 그리고 source의 실제 값과 provenance를 다시 대조한다.

반례 반례에서는 `notification URL·시각·screenshot hash 없이는 외부 실행이 아니다` 상태인데도 Green을 주장하게 된다.

11

STEP 11 / 13

이 코드가 보장하지 않는 것

이 코드가 책임지지 않는 일을 분리합니다.

직접 미보장

notification URL·시각·screenshot hash 없이는 외부 실행이 아니다

이 책임을 맡는 곳: metric/query grain
직접 미보장

학습 threshold는 운영 SLA가 아니다

이 책임을 맡는 곳: 별도 local/external 실행
직접 미보장

업무 409를 5xx에 합산하지 않는다

이 책임을 맡는 곳: secret·개인정보·운영 정책
직접 미보장

문서 작성만으로 alert delivery가 증명되지 않는다

이 책임을 맡는 곳: infrastructure·사람 검토
12

STEP 12 / 13

직접 다시 써보기

뜻 → 조각 → 전체 코드 순서로 다시 씁니다.

1단계 · 뜻부터 복원

다음 역할을 고정값과 미보장 경계까지 말한다: High5xx·SlowTransfer·LedgerMismatch 세 알림의 조건·window·severity·owner·action·runbook·clear를 적는 학습 template이다.

2단계 · 코드 조각 재조립

  1. 원문 1–10줄
  2. 원문 11–11줄

3단계 · 파일 전체 다시 쓰기

11개 물리 줄을 원본 순서로 복원하고 SHA-256 b06540f4b92c2e3e36a910ac2759fadfd6f1e8c202c9d134894dee2af872141f와 대조한다.

자가 점검
  • 원본 source/template bytes와 줄 번호를 바꾸지 않았는가?
  • 정본 3개와 학습용 예시 8개를 구분했는가?
  • RequestId local Gate와 DB wait local drill의 Green 범위를 분리했는가?
  • dashboard·alert·incident timeline을 NOT_RUN_EXTERNAL 또는 사람 검토로 남겼는가?
  • Q37의 JOIN grain과 Q38의 SUCCESS·반개구간 가정을 드러냈는가?
13

STEP 13 / 13

전체 원본 source

감사로 고정한 전체 source를 가감 없이 확인합니다.

학습용 예시 전체 확인하기 · 정본 답안 아님
학습용 예시 · alert/runbook template · 정본 답안 아님 · 외부 미실행illustrative/markdown/W23-D5-alerts.mdSHA-256 b06540f4b92c2e3e36a910ac2759fadfd6f1e8c202c9d134894dee2af872141f
D5 alerts — 5xx·p95·ledger mismatch 세 경보의 조건과 사람 대응 전체
# W23 alert 3종 학습용 예시 - 사람 검토 전 Green 아님

| 이름 | 조건 | window | severity | owner | first query/action | runbook | clear |
|---|---|---|---|---|---|---|---|
| High5xx | 5xx_rate > 2% | 5분 지속 | SEV2 | API on-call | requestId sample과 route/status 확인 | runbooks/db-timeout.md | 10분간 1% 미만 |
| SlowTransfer | p95 > 1000ms | 10분 지속 | SEV2 | transfer on-call | pool pending과 DB lock wait를 분리 확인 | runbooks/db-timeout.md | 10분간 p95 < 500ms |
| LedgerMismatch | mismatch_count > 0 | 대사 1회 | SEV1 | finance ops | 재처리 중지, 영향 계좌 격리, source 대조 | runbooks/ledger-mismatch.md | 승인된 correction 뒤 mismatch 0 |

- 업무 409 거절은 5xx 장애율에 합산하지 않는다.
- notification URL, 실행시각, screenshot SHA-256이 없으면 `NOT_RUN_EXTERNAL`이다.
- threshold는 학습 baseline이며 운영 SLA라고 주장하지 않는다.
09

W23-SQL-Q38 — 두 반개구간 모두 거래한 고객을 INTERSECT로 찾기

illustrative/sql/W23-SQL-Q38.sql

학습용 예시 · Q37/Q38 prompt 기반 SQL · 정본 답안 아님 · 학습용 예시 · 정본 답안 아님 · W23-F09
30줄 연결30줄 번역4 chunks
01

STEP 01 / 13

오늘 이 코드에서 해결할 문제

무엇을 이해해야 하는지 질문부터 잡습니다.

오늘의 한 문장

두 반개구간 모두에서 성공 거래가 있는 고객을 DISTINCT와 INTERSECT로 한 번만 반환하는 비정본 Q38 예시다.

  1. `status=SUCCESS`은 어느 줄에서 생기거나 검증될까?
  2. 입력→guard→관찰→cleanup 또는 stable output 순서는 무엇인가?
  3. local 자동 owner와 external human owner는 각각 누구인가?
  4. 이 source가 직접 관찰하지 않은 Green은 무엇인가?
  5. 반례는 `workbook 제공 정답이 아니다` 경계와 어떻게 연결되는가?
이 파일에서 끝까지 다시 쓰는 값status=SUCCESShalf-open periodsDISTINCTINTERSECTcustomer_id=1 김민수
02

STEP 02 / 13

아주 짧게: 이 코드는 왜 필요할까?

웹소설 대신 이 코드가 필요한 이유만 두 문단으로 쉽게 봅니다.

STARRY가 metric catalog·requestId 봉투·DB wait 영수증·alert/runbook·SQL grain 표를 서로 다른 칸에 놓는다.

W23-SQL-Q38 — 두 반개구간 모두 거래한 고객을 INTERSECT로 찾기 ― 관측 증거 흐름으로 바꾸기

두 반개구간 모두에서 성공 거래가 있는 고객을 DISTINCT와 INTERSECT로 한 번만 반환하는 비정본 Q38 예시다.

핵심값 status=SUCCESS, half-open periods, DISTINCT, INTERSECT, customer_id=1 김민수을 원본 줄로 따라가되, `workbook 제공 정답이 아니다`까지 함께 표시해 local 관찰을 외부 운영 Green으로 부풀리지 않는다.

딱 여기까지만 비유는 grain·owner·순서를 기억하게 할 뿐 실제 Gradle/Docker/PostgreSQL 실행, dashboard·notification, 운영 SLA를 자동 증명하지 않는다.

03

STEP 03 / 13

초등학생도 이해하는 설명

생활 비유와 실제 코드의 경계를 함께 확인합니다.

원문 1–10줄

1~10줄을 한 덩어리로 읽어 1번째 움직임을 본다. 두 반개구간 모두에서 성공 거래가 있는 고객을 DISTINCT와 INTERSECT로 한 번만 반환하는 비정본 Q38 예시다.

코드 연결
1~10줄
비유
여름 출석 명단과 겨울 출석 명단을 각각 중복 없이 만든 뒤, 두 명단에 모두 있는 사람만 남기는 교집합 검사
비유의 끝
workbook 제공 정답이 아니다

원문 11–20줄

11~20줄을 한 덩어리로 읽어 2번째 움직임을 본다. 두 반개구간 모두에서 성공 거래가 있는 고객을 DISTINCT와 INTERSECT로 한 번만 반환하는 비정본 Q38 예시다.

코드 연결
11~20줄
비유
여름 출석 명단과 겨울 출석 명단을 각각 중복 없이 만든 뒤, 두 명단에 모두 있는 사람만 남기는 교집합 검사
비유의 끝
기간·timezone·status는 명시한 학습 가정이다

원문 21–30줄

21~30줄을 한 덩어리로 읽어 3번째 움직임을 본다. 두 반개구간 모두에서 성공 거래가 있는 고객을 DISTINCT와 INTERSECT로 한 번만 반환하는 비정본 Q38 예시다.

코드 연결
21~30줄
비유
여름 출석 명단과 겨울 출석 명단을 각각 중복 없이 만든 뒤, 두 명단에 모두 있는 사람만 남기는 교집합 검사
비유의 끝
여러 거래를 고객 중복 행으로 내지 않는다
문제의 첫 장면히토리 → 니지카 → 료 → 키타
  1. 히토리

    첫 고정값은 `status=SUCCESS` 맞아?

  2. 니지카

    두 반개구간 모두에서 성공 거래가 있는 고객을 DISTINCT와 INTERSECT로 한 번만 반환하는 비정본 Q38 예시다.

  3. 원문에서 `status=SUCCESS`이 만들어지거나 확인되는 줄을 찾자.

  4. 키타

    그리고 `workbook 제공 정답이 아니다`도 같이 적어.

입력에서 결과까지히토리 → 니지카 → 료 → 키타
  1. 히토리

    `half-open periods`은 언제 생겨?

  2. 니지카

    period A의 성공 고객 집합을 만든다. → period B의 성공 고객 집합을 만든다.

  3. INTERSECT로 공통 customer_id를 구한다. → customer를 JOIN하고 stable order로 출력한다.

  4. 키타

    관찰값과 `기간·timezone·status는 명시한 학습 가정이다`을 분리하면 돼.

04

STEP 04 / 13

비유 ↔ 코드 전체 연결표

감사 규칙상 연결 대상인 원본 30줄을 빠짐없이 연결합니다.

단어 몇 개만 뽑은 표가 아닙니다.학습용 예시 · Q37/Q38 prompt 기반 SQL · 정본 답안 아님에서 비어 있지 않은 모든 줄을 원본 줄 번호 그대로 연결했습니다.30 / 30 연결
정확한 원본 줄STARRY 비유실제 뜻·입력·결과·한계
1줄F09-L01 -- 학습용 예시 · 정본 답안 아님 여름 출석 명단과 겨울 출석 명단을 각각 중복 없이 만든 뒤, 두 명단에 모두 있는 사람만 남기는 교집합 검사 이 source의 provenance·grain·가정·반례·실행 경계를 사람이 확인할 설명 줄이다.
입력
두 반개구간의 SUCCESS business_tx·account·customer
결과·효과
이 줄 뒤에는 항목 전체의 `status=SUCCESS` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
workbook 제공 정답이 아니다
2줄F09-L02 -- 가정: 거래는 status='SUCCESS'이며 두 기간은 [start, end) 반개구간이다. 여름 출석 명단과 겨울 출석 명단을 각각 중복 없이 만든 뒤, 두 명단에 모두 있는 사람만 남기는 교집합 검사 이 source의 provenance·grain·가정·반례·실행 경계를 사람이 확인할 설명 줄이다.
입력
두 반개구간의 SUCCESS business_tx·account·customer
결과·효과
이 줄 뒤에는 항목 전체의 `half-open periods` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
기간·timezone·status는 명시한 학습 가정이다
3줄F09-L03 -- 입력 grain: business_tx 1행/거래. 출력 grain: customer 1행. 여름 출석 명단과 겨울 출석 명단을 각각 중복 없이 만든 뒤, 두 명단에 모두 있는 사람만 남기는 교집합 검사 이 source의 provenance·grain·가정·반례·실행 경계를 사람이 확인할 설명 줄이다.
입력
두 반개구간의 SUCCESS business_tx·account·customer
결과·효과
이 줄 뒤에는 항목 전체의 `DISTINCT` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
여러 거래를 고객 중복 행으로 내지 않는다
5줄F09-L05 WITH period_a AS ( 여름 출석 명단과 겨울 출석 명단을 각각 중복 없이 만든 뒤, 두 명단에 모두 있는 사람만 남기는 교집합 검사 첫 반개구간의 SUCCESS 거래 고객 집합을 만드는 CTE를 연다.
입력
두 반개구간의 SUCCESS business_tx·account·customer
결과·효과
이 줄 뒤에는 항목 전체의 `customer_id=1 김민수` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
workbook 제공 정답이 아니다
6줄F09-L06 SELECT DISTINCT a.customer_id 여름 출석 명단과 겨울 출석 명단을 각각 중복 없이 만든 뒤, 두 명단에 모두 있는 사람만 남기는 교집합 검사 SQL의 입력 grain·연결·필터·집계·stable 출력 순서를 구성하는 절이다.
입력
두 반개구간의 SUCCESS business_tx·account·customer
결과·효과
이 줄 뒤에는 항목 전체의 `status=SUCCESS` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
기간·timezone·status는 명시한 학습 가정이다
7줄F09-L07 FROM business_tx AS tx 여름 출석 명단과 겨울 출석 명단을 각각 중복 없이 만든 뒤, 두 명단에 모두 있는 사람만 남기는 교집합 검사 SQL의 입력 grain·연결·필터·집계·stable 출력 순서를 구성하는 절이다.
입력
두 반개구간의 SUCCESS business_tx·account·customer
결과·효과
이 줄 뒤에는 항목 전체의 `half-open periods` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
여러 거래를 고객 중복 행으로 내지 않는다
8줄F09-L08 JOIN account AS a ON a.account_id = tx.account_id 여름 출석 명단과 겨울 출석 명단을 각각 중복 없이 만든 뒤, 두 명단에 모두 있는 사람만 남기는 교집합 검사 SQL의 입력 grain·연결·필터·집계·stable 출력 순서를 구성하는 절이다.
입력
두 반개구간의 SUCCESS business_tx·account·customer
결과·효과
이 줄 뒤에는 항목 전체의 `DISTINCT` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
fixture 예상은 실제 query 실행 결과가 아니다
9줄F09-L09 WHERE tx.status = 'SUCCESS' 여름 출석 명단과 겨울 출석 명단을 각각 중복 없이 만든 뒤, 두 명단에 모두 있는 사람만 남기는 교집합 검사 SQL의 입력 grain·연결·필터·집계·stable 출력 순서를 구성하는 절이다.
입력
두 반개구간의 SUCCESS business_tx·account·customer
결과·효과
이 줄 뒤에는 항목 전체의 `INTERSECT` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
workbook 제공 정답이 아니다
10줄F09-L10 AND tx.occurred_at >= TIMESTAMPTZ '2026-06-30 00:00:00+09' 여름 출석 명단과 겨울 출석 명단을 각각 중복 없이 만든 뒤, 두 명단에 모두 있는 사람만 남기는 교집합 검사 기간 경계를 명시적 +09 timezone의 timestamp로 고정한다.
입력
두 반개구간의 SUCCESS business_tx·account·customer
결과·효과
이 줄 뒤에는 항목 전체의 `customer_id=1 김민수` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
기간·timezone·status는 명시한 학습 가정이다
11줄F09-L11 AND tx.occurred_at < TIMESTAMPTZ '2026-07-03 00:00:00+09' 여름 출석 명단과 겨울 출석 명단을 각각 중복 없이 만든 뒤, 두 명단에 모두 있는 사람만 남기는 교집합 검사 기간 경계를 명시적 +09 timezone의 timestamp로 고정한다.
입력
두 반개구간의 SUCCESS business_tx·account·customer
결과·효과
이 줄 뒤에는 항목 전체의 `status=SUCCESS` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
여러 거래를 고객 중복 행으로 내지 않는다
12줄F09-L12 ), 여름 출석 명단과 겨울 출석 명단을 각각 중복 없이 만든 뒤, 두 명단에 모두 있는 사람만 남기는 교집합 검사 비정본 Q38 두 기간 교집합 SQL의 12번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
입력
두 반개구간의 SUCCESS business_tx·account·customer
결과·효과
이 줄 뒤에는 항목 전체의 `half-open periods` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
fixture 예상은 실제 query 실행 결과가 아니다
13줄F09-L13 period_b AS ( 여름 출석 명단과 겨울 출석 명단을 각각 중복 없이 만든 뒤, 두 명단에 모두 있는 사람만 남기는 교집합 검사 둘째 반개구간의 SUCCESS 거래 고객 집합을 만든다.
입력
두 반개구간의 SUCCESS business_tx·account·customer
결과·효과
이 줄 뒤에는 항목 전체의 `DISTINCT` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
workbook 제공 정답이 아니다
14줄F09-L14 SELECT DISTINCT a.customer_id 여름 출석 명단과 겨울 출석 명단을 각각 중복 없이 만든 뒤, 두 명단에 모두 있는 사람만 남기는 교집합 검사 SQL의 입력 grain·연결·필터·집계·stable 출력 순서를 구성하는 절이다.
입력
두 반개구간의 SUCCESS business_tx·account·customer
결과·효과
이 줄 뒤에는 항목 전체의 `INTERSECT` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
기간·timezone·status는 명시한 학습 가정이다
15줄F09-L15 FROM business_tx AS tx 여름 출석 명단과 겨울 출석 명단을 각각 중복 없이 만든 뒤, 두 명단에 모두 있는 사람만 남기는 교집합 검사 SQL의 입력 grain·연결·필터·집계·stable 출력 순서를 구성하는 절이다.
입력
두 반개구간의 SUCCESS business_tx·account·customer
결과·효과
이 줄 뒤에는 항목 전체의 `customer_id=1 김민수` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
여러 거래를 고객 중복 행으로 내지 않는다
16줄F09-L16 JOIN account AS a ON a.account_id = tx.account_id 여름 출석 명단과 겨울 출석 명단을 각각 중복 없이 만든 뒤, 두 명단에 모두 있는 사람만 남기는 교집합 검사 SQL의 입력 grain·연결·필터·집계·stable 출력 순서를 구성하는 절이다.
입력
두 반개구간의 SUCCESS business_tx·account·customer
결과·효과
이 줄 뒤에는 항목 전체의 `status=SUCCESS` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
fixture 예상은 실제 query 실행 결과가 아니다
17줄F09-L17 WHERE tx.status = 'SUCCESS' 여름 출석 명단과 겨울 출석 명단을 각각 중복 없이 만든 뒤, 두 명단에 모두 있는 사람만 남기는 교집합 검사 SQL의 입력 grain·연결·필터·집계·stable 출력 순서를 구성하는 절이다.
입력
두 반개구간의 SUCCESS business_tx·account·customer
결과·효과
이 줄 뒤에는 항목 전체의 `half-open periods` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
workbook 제공 정답이 아니다
18줄F09-L18 AND tx.occurred_at >= TIMESTAMPTZ '2026-12-28 00:00:00+09' 여름 출석 명단과 겨울 출석 명단을 각각 중복 없이 만든 뒤, 두 명단에 모두 있는 사람만 남기는 교집합 검사 기간 경계를 명시적 +09 timezone의 timestamp로 고정한다.
입력
두 반개구간의 SUCCESS business_tx·account·customer
결과·효과
이 줄 뒤에는 항목 전체의 `DISTINCT` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
기간·timezone·status는 명시한 학습 가정이다
19줄F09-L19 AND tx.occurred_at < TIMESTAMPTZ '2027-01-03 00:00:00+09' 여름 출석 명단과 겨울 출석 명단을 각각 중복 없이 만든 뒤, 두 명단에 모두 있는 사람만 남기는 교집합 검사 기간 경계를 명시적 +09 timezone의 timestamp로 고정한다.
입력
두 반개구간의 SUCCESS business_tx·account·customer
결과·효과
이 줄 뒤에는 항목 전체의 `INTERSECT` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
여러 거래를 고객 중복 행으로 내지 않는다
20줄F09-L20 ), 여름 출석 명단과 겨울 출석 명단을 각각 중복 없이 만든 뒤, 두 명단에 모두 있는 사람만 남기는 교집합 검사 비정본 Q38 두 기간 교집합 SQL의 20번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
입력
두 반개구간의 SUCCESS business_tx·account·customer
결과·효과
이 줄 뒤에는 항목 전체의 `customer_id=1 김민수` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
fixture 예상은 실제 query 실행 결과가 아니다
21줄F09-L21 both_periods AS ( 여름 출석 명단과 겨울 출석 명단을 각각 중복 없이 만든 뒤, 두 명단에 모두 있는 사람만 남기는 교집합 검사 비정본 Q38 두 기간 교집합 SQL의 21번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
입력
두 반개구간의 SUCCESS business_tx·account·customer
결과·효과
이 줄 뒤에는 항목 전체의 `status=SUCCESS` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
workbook 제공 정답이 아니다
22줄F09-L22 SELECT customer_id FROM period_a 여름 출석 명단과 겨울 출석 명단을 각각 중복 없이 만든 뒤, 두 명단에 모두 있는 사람만 남기는 교집합 검사 SQL의 입력 grain·연결·필터·집계·stable 출력 순서를 구성하는 절이다.
입력
두 반개구간의 SUCCESS business_tx·account·customer
결과·효과
이 줄 뒤에는 항목 전체의 `half-open periods` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
기간·timezone·status는 명시한 학습 가정이다
23줄F09-L23 INTERSECT 여름 출석 명단과 겨울 출석 명단을 각각 중복 없이 만든 뒤, 두 명단에 모두 있는 사람만 남기는 교집합 검사 두 기간에 모두 존재하는 customer_id만 중복 없이 남긴다.
입력
두 반개구간의 SUCCESS business_tx·account·customer
결과·효과
이 줄 뒤에는 항목 전체의 `DISTINCT` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
여러 거래를 고객 중복 행으로 내지 않는다
24줄F09-L24 SELECT customer_id FROM period_b 여름 출석 명단과 겨울 출석 명단을 각각 중복 없이 만든 뒤, 두 명단에 모두 있는 사람만 남기는 교집합 검사 둘째 반개구간의 SUCCESS 거래 고객 집합을 만든다.
입력
두 반개구간의 SUCCESS business_tx·account·customer
결과·효과
이 줄 뒤에는 항목 전체의 `INTERSECT` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
fixture 예상은 실제 query 실행 결과가 아니다
25줄F09-L25 ) 여름 출석 명단과 겨울 출석 명단을 각각 중복 없이 만든 뒤, 두 명단에 모두 있는 사람만 남기는 교집합 검사 현재 object·array·block 또는 query 범위를 열거나 닫아 구조와 실행 순서를 유지한다.
입력
두 반개구간의 SUCCESS business_tx·account·customer
결과·효과
이 줄 뒤에는 항목 전체의 `customer_id=1 김민수` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
workbook 제공 정답이 아니다
26줄F09-L26 SELECT c.customer_id, c.customer_name 여름 출석 명단과 겨울 출석 명단을 각각 중복 없이 만든 뒤, 두 명단에 모두 있는 사람만 남기는 교집합 검사 SQL의 입력 grain·연결·필터·집계·stable 출력 순서를 구성하는 절이다.
입력
두 반개구간의 SUCCESS business_tx·account·customer
결과·효과
이 줄 뒤에는 항목 전체의 `status=SUCCESS` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
기간·timezone·status는 명시한 학습 가정이다
27줄F09-L27 FROM both_periods AS b 여름 출석 명단과 겨울 출석 명단을 각각 중복 없이 만든 뒤, 두 명단에 모두 있는 사람만 남기는 교집합 검사 SQL의 입력 grain·연결·필터·집계·stable 출력 순서를 구성하는 절이다.
입력
두 반개구간의 SUCCESS business_tx·account·customer
결과·효과
이 줄 뒤에는 항목 전체의 `half-open periods` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
여러 거래를 고객 중복 행으로 내지 않는다
28줄F09-L28 JOIN customer AS c ON c.customer_id = b.customer_id 여름 출석 명단과 겨울 출석 명단을 각각 중복 없이 만든 뒤, 두 명단에 모두 있는 사람만 남기는 교집합 검사 SQL의 입력 grain·연결·필터·집계·stable 출력 순서를 구성하는 절이다.
입력
두 반개구간의 SUCCESS business_tx·account·customer
결과·효과
이 줄 뒤에는 항목 전체의 `DISTINCT` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
fixture 예상은 실제 query 실행 결과가 아니다
29줄F09-L29 ORDER BY c.customer_id; 여름 출석 명단과 겨울 출석 명단을 각각 중복 없이 만든 뒤, 두 명단에 모두 있는 사람만 남기는 교집합 검사 SQL의 입력 grain·연결·필터·집계·stable 출력 순서를 구성하는 절이다.
입력
두 반개구간의 SUCCESS business_tx·account·customer
결과·효과
이 줄 뒤에는 항목 전체의 `INTERSECT` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
workbook 제공 정답이 아니다
31줄F09-L31 -- workbook fixture 예상: customer_id=1, 김민수 한 행. 여름 출석 명단과 겨울 출석 명단을 각각 중복 없이 만든 뒤, 두 명단에 모두 있는 사람만 남기는 교집합 검사 이 source의 provenance·grain·가정·반례·실행 경계를 사람이 확인할 설명 줄이다.
입력
두 반개구간의 SUCCESS business_tx·account·customer
결과·효과
이 줄 뒤에는 항목 전체의 `status=SUCCESS` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
여러 거래를 고객 중복 행으로 내지 않는다
32줄F09-L32 -- DISTINCT/INTERSECT가 없으면 같은 고객의 여러 거래 때문에 중복될 수 있다. 여름 출석 명단과 겨울 출석 명단을 각각 중복 없이 만든 뒤, 두 명단에 모두 있는 사람만 남기는 교집합 검사 두 기간에 모두 존재하는 customer_id만 중복 없이 남긴다.
입력
두 반개구간의 SUCCESS business_tx·account·customer
결과·효과
이 줄 뒤에는 항목 전체의 `half-open periods` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
fixture 예상은 실제 query 실행 결과가 아니다
Green 범위히토리 → 니지카 → 료 → 키타
  1. 히토리

    marker나 문서가 보이면 W23 전체 성공이야?

  2. 니지카

    아니. 이 source가 직접 검증한 claim만 말해야 해.

  3. 직접 연결되는 대표 값은 `customer_id=1 김민수`이야.

  4. 키타

    `여러 거래를 고객 중복 행으로 내지 않는다`는 별도 실행·사람 증거가 필요해.

05

STEP 05 / 13

원본 코드 조각

원본을 4개 의미 조각으로 나누어 그대로 확인합니다.

파일을 한꺼번에 외우지 않고 실행 의미가 이어지는 작은 조각으로 봅니다. 아래 코드는 prompt·fixture·가정을 밝힌 학습용 예시 source이며, 제공 정본 답안이 아닙니다.

F09-C01 · 원문 1–10줄1–10줄
1–10줄 원본
-- 학습용 예시 · 정본 답안 아님
-- 가정: 거래는 status='SUCCESS'이며 두 기간은 [start, end) 반개구간이다.
-- 입력 grain: business_tx 1행/거래. 출력 grain: customer 1행.

WITH period_a AS (
    SELECT DISTINCT a.customer_id
    FROM business_tx AS tx
    JOIN account AS a ON a.account_id = tx.account_id
    WHERE tx.status = 'SUCCESS'
      AND tx.occurred_at >= TIMESTAMPTZ '2026-06-30 00:00:00+09'
F09-C02 · 원문 11–20줄11–20줄
11–20줄 원본
      AND tx.occurred_at <  TIMESTAMPTZ '2026-07-03 00:00:00+09'
),
period_b AS (
    SELECT DISTINCT a.customer_id
    FROM business_tx AS tx
    JOIN account AS a ON a.account_id = tx.account_id
    WHERE tx.status = 'SUCCESS'
      AND tx.occurred_at >= TIMESTAMPTZ '2026-12-28 00:00:00+09'
      AND tx.occurred_at <  TIMESTAMPTZ '2027-01-03 00:00:00+09'
),
F09-C03 · 원문 21–30줄21–30줄
21–30줄 원본
both_periods AS (
    SELECT customer_id FROM period_a
    INTERSECT
    SELECT customer_id FROM period_b
)
SELECT c.customer_id, c.customer_name
FROM both_periods AS b
JOIN customer AS c ON c.customer_id = b.customer_id
ORDER BY c.customer_id;
F09-C04 · 원문 31–32줄31–32줄
31–32줄 원본
-- workbook fixture 예상: customer_id=1, 김민수 한 행.
-- DISTINCT/INTERSECT가 없으면 같은 고객의 여러 거래 때문에 중복될 수 있다.
06

STEP 06 / 13

코드 한 줄씩 한국어로 번역

비어 있지 않은 30줄을 모두 한국어로 옮깁니다.

전체 번역 30 / 30

비어 있지 않은 원본 줄은 하나도 생략하지 않습니다.

원본한국어 번역
1-- 학습용 예시 · 정본 답안 아님이 source의 provenance·grain·가정·반례·실행 경계를 사람이 확인할 설명 줄이다.
2-- 가정: 거래는 status='SUCCESS'이며 두 기간은 [start, end) 반개구간이다.이 source의 provenance·grain·가정·반례·실행 경계를 사람이 확인할 설명 줄이다.
3-- 입력 grain: business_tx 1행/거래. 출력 grain: customer 1행.이 source의 provenance·grain·가정·반례·실행 경계를 사람이 확인할 설명 줄이다.
5WITH period_a AS (첫 반개구간의 SUCCESS 거래 고객 집합을 만드는 CTE를 연다.
6 SELECT DISTINCT a.customer_idSQL의 입력 grain·연결·필터·집계·stable 출력 순서를 구성하는 절이다.
7 FROM business_tx AS txSQL의 입력 grain·연결·필터·집계·stable 출력 순서를 구성하는 절이다.
8 JOIN account AS a ON a.account_id = tx.account_idSQL의 입력 grain·연결·필터·집계·stable 출력 순서를 구성하는 절이다.
9 WHERE tx.status = 'SUCCESS'SQL의 입력 grain·연결·필터·집계·stable 출력 순서를 구성하는 절이다.
10 AND tx.occurred_at >= TIMESTAMPTZ '2026-06-30 00:00:00+09'기간 경계를 명시적 +09 timezone의 timestamp로 고정한다.
11 AND tx.occurred_at < TIMESTAMPTZ '2026-07-03 00:00:00+09'기간 경계를 명시적 +09 timezone의 timestamp로 고정한다.
12),비정본 Q38 두 기간 교집합 SQL의 12번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
13period_b AS (둘째 반개구간의 SUCCESS 거래 고객 집합을 만든다.
14 SELECT DISTINCT a.customer_idSQL의 입력 grain·연결·필터·집계·stable 출력 순서를 구성하는 절이다.
15 FROM business_tx AS txSQL의 입력 grain·연결·필터·집계·stable 출력 순서를 구성하는 절이다.
16 JOIN account AS a ON a.account_id = tx.account_idSQL의 입력 grain·연결·필터·집계·stable 출력 순서를 구성하는 절이다.
17 WHERE tx.status = 'SUCCESS'SQL의 입력 grain·연결·필터·집계·stable 출력 순서를 구성하는 절이다.
18 AND tx.occurred_at >= TIMESTAMPTZ '2026-12-28 00:00:00+09'기간 경계를 명시적 +09 timezone의 timestamp로 고정한다.
19 AND tx.occurred_at < TIMESTAMPTZ '2027-01-03 00:00:00+09'기간 경계를 명시적 +09 timezone의 timestamp로 고정한다.
20),비정본 Q38 두 기간 교집합 SQL의 20번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
21both_periods AS (비정본 Q38 두 기간 교집합 SQL의 21번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
22 SELECT customer_id FROM period_aSQL의 입력 grain·연결·필터·집계·stable 출력 순서를 구성하는 절이다.
23 INTERSECT두 기간에 모두 존재하는 customer_id만 중복 없이 남긴다.
24 SELECT customer_id FROM period_b둘째 반개구간의 SUCCESS 거래 고객 집합을 만든다.
25)현재 object·array·block 또는 query 범위를 열거나 닫아 구조와 실행 순서를 유지한다.
26SELECT c.customer_id, c.customer_nameSQL의 입력 grain·연결·필터·집계·stable 출력 순서를 구성하는 절이다.
27FROM both_periods AS bSQL의 입력 grain·연결·필터·집계·stable 출력 순서를 구성하는 절이다.
28JOIN customer AS c ON c.customer_id = b.customer_idSQL의 입력 grain·연결·필터·집계·stable 출력 순서를 구성하는 절이다.
29ORDER BY c.customer_id;SQL의 입력 grain·연결·필터·집계·stable 출력 순서를 구성하는 절이다.
31-- workbook fixture 예상: customer_id=1, 김민수 한 행.이 source의 provenance·grain·가정·반례·실행 경계를 사람이 확인할 설명 줄이다.
32-- DISTINCT/INTERSECT가 없으면 같은 고객의 여러 거래 때문에 중복될 수 있다.두 기간에 모두 존재하는 customer_id만 중복 없이 남긴다.
07

STEP 07 / 13

기존 수준의 한 줄 읽기·문법 해부

쉬운 설명 다음에 문법과 실행 순서를 정밀하게 읽습니다.

한 줄로 읽기

두 반개구간 모두에서 성공 거래가 있는 고객을 DISTINCT와 INTERSECT로 한 번만 반환하는 비정본 Q38 예시다. 다만 workbook 제공 정답이 아니다

문법 해부

  • 각 period CTE는 SUCCESS 거래를 반개구간 `[start,end)`로 거른 뒤 customer_id를 DISTINCT한다.
  • `INTERSECT`가 두 customer 집합의 공통 원소만 남기고 마지막 JOIN이 이름을 붙인다.

실행 순서

  1. period A의 성공 고객 집합을 만든다.
  2. period B의 성공 고객 집합을 만든다.
  3. INTERSECT로 공통 customer_id를 구한다.
  4. customer를 JOIN하고 stable order로 출력한다.

W23 조각별 정밀 해설

F09-C01 · 원문 1–10줄
문법 해부
1~10줄의 `원문 1–10줄`을 입력·grain/guard·관찰·cleanup/stable output 단계로 나눈다.
실제 값 추적
항목 전체 흐름에 연결해 `status=SUCCESS`을 대조한다. 이 값이 chunk 단독 산출이라는 뜻은 아니다.
정상 예
정상 예에서는 source 순서와 owner 계약이 일치해 `status=SUCCESS`을 관찰한다.
틀린 예·반례
반례에서는 선행 guard·grain·stable order·cleanup을 생략한다. 동결 경계: workbook 제공 정답이 아니다.
착각 방지
`원문 1–10줄`이 항목 전체 또는 외부 운영 Green을 단독 증명한다고 읽지 않는다.
하지 않는 일
이 chunk가 책임지지 않는 범위: workbook 제공 정답이 아니다.
다음 연결
다음 source chunk의 입력 또는 exact local marker·SQL oracle·사람 검토 경계로 결과를 넘긴다.
F09-C02 · 원문 11–20줄
문법 해부
11~20줄의 `원문 11–20줄`을 입력·grain/guard·관찰·cleanup/stable output 단계로 나눈다.
실제 값 추적
항목 전체 흐름에 연결해 `half-open periods`을 대조한다. 이 값이 chunk 단독 산출이라는 뜻은 아니다.
정상 예
정상 예에서는 source 순서와 owner 계약이 일치해 `half-open periods`을 관찰한다.
틀린 예·반례
반례에서는 선행 guard·grain·stable order·cleanup을 생략한다. 동결 경계: 기간·timezone·status는 명시한 학습 가정이다.
착각 방지
`원문 11–20줄`이 항목 전체 또는 외부 운영 Green을 단독 증명한다고 읽지 않는다.
하지 않는 일
이 chunk가 책임지지 않는 범위: 기간·timezone·status는 명시한 학습 가정이다.
다음 연결
다음 source chunk의 입력 또는 exact local marker·SQL oracle·사람 검토 경계로 결과를 넘긴다.
F09-C03 · 원문 21–30줄
문법 해부
21~30줄의 `원문 21–30줄`을 입력·grain/guard·관찰·cleanup/stable output 단계로 나눈다.
실제 값 추적
항목 전체 흐름에 연결해 `DISTINCT`을 대조한다. 이 값이 chunk 단독 산출이라는 뜻은 아니다.
정상 예
정상 예에서는 source 순서와 owner 계약이 일치해 `DISTINCT`을 관찰한다.
틀린 예·반례
반례에서는 선행 guard·grain·stable order·cleanup을 생략한다. 동결 경계: 여러 거래를 고객 중복 행으로 내지 않는다.
착각 방지
`원문 21–30줄`이 항목 전체 또는 외부 운영 Green을 단독 증명한다고 읽지 않는다.
하지 않는 일
이 chunk가 책임지지 않는 범위: 여러 거래를 고객 중복 행으로 내지 않는다.
다음 연결
다음 source chunk의 입력 또는 exact local marker·SQL oracle·사람 검토 경계로 결과를 넘긴다.
F09-C04 · 원문 31–32줄
문법 해부
31~32줄의 `원문 31–32줄`을 입력·grain/guard·관찰·cleanup/stable output 단계로 나눈다.
실제 값 추적
항목 전체 흐름에 연결해 `INTERSECT`을 대조한다. 이 값이 chunk 단독 산출이라는 뜻은 아니다.
정상 예
정상 예에서는 source 순서와 owner 계약이 일치해 `INTERSECT`을 관찰한다.
틀린 예·반례
반례에서는 선행 guard·grain·stable order·cleanup을 생략한다. 동결 경계: fixture 예상은 실제 query 실행 결과가 아니다.
착각 방지
`원문 31–32줄`이 항목 전체 또는 외부 운영 Green을 단독 증명한다고 읽지 않는다.
하지 않는 일
이 chunk가 책임지지 않는 범위: fixture 예상은 실제 query 실행 결과가 아니다.
다음 연결
다음 source chunk의 입력 또는 exact local marker·SQL oracle·사람 검토 경계로 결과를 넘긴다.
반례히토리 → 니지카 → 료 → 키타
  1. 히토리

    겉보기에는 맞지만 깨지는 예는?

  2. 니지카

    OR로 두 기간 중 하나만 거래한 고객도 포함한다

  3. 그 상태는 입력 grain·owner·관찰 중 한 칸이 비어 있어.

  4. 키타

    수정한 뒤 같은 source bytes와 evidence를 다시 대조해.

08

STEP 08 / 13

실제 값 따라가기

같은 입력값이 어느 줄을 지나 어떤 결과가 되는지 추적합니다.

순서들어온 값코드가 하는 일나온 값·상태경계
F09-T01 A2026-06-30≤t<2026-07-03DISTINCTcustomer set AKST 가정
F09-T02 B2026-12-28≤t<2027-01-03DISTINCTcustomer set BSUCCESS만
F09-T03 bothA and BINTERSECTfixture customer 1 김민수prompt-only oracle
책임 경계히토리 → 니지카 → 료 → 키타
  1. 히토리

    이 항목의 마지막 책임선은?

  2. 니지카

    직접 역할은 `비정본 Q38 두 기간 교집합 SQL`이야.

  3. 대표 경계는 `fixture 예상은 실제 query 실행 결과가 아니다`이야.

  4. 키타

    정본/학습용 label과 local/external owner까지 확인하면 끝이야.

09

STEP 09 / 13

Micrometer·RequestId·PowerShell·PostgreSQL 내부에서 벌어지는 일

Micrometer·JUnit·PowerShell·PostgreSQL·alert/runbook에서 실제로 일어나는 일과 증명 범위를 구분합니다.

half-open range

끝 시각을 다음 구간에 한 번만 포함하게 한다.

timezone 정책은 명시한 +09 가정에 의존한다.
DISTINCT

한 기간의 여러 거래를 고객 한 값으로 줄인다.

거래 금액·횟수는 보존하지 않는다.
INTERSECT

두 집합 모두에 존재하는 값을 중복 없이 반환한다.

기간 중 하나만 거래한 고객은 제외한다.
10

STEP 10 / 13

흔한 착각과 틀린 예

그럴듯하지만 틀린 해석을 반례로 고칩니다.

❌ OR로 두 기간 중 하나만 거래한 고객도 포함한다

왜 틀리나 비정본 Q38 두 기간 교집합 SQL의 grain·owner·관찰·경계 중 적어도 하나를 건너뛴다.

바르게 읽기 period A의 성공 고객 집합을 만든다. 그리고 source의 실제 값과 provenance를 다시 대조한다.

반례 반례에서는 `workbook 제공 정답이 아니다` 상태인데도 Green을 주장하게 된다.

❌ BETWEEN으로 끝 경계를 중복 포함한다

왜 틀리나 비정본 Q38 두 기간 교집합 SQL의 grain·owner·관찰·경계 중 적어도 하나를 건너뛴다.

바르게 읽기 period B의 성공 고객 집합을 만든다. 그리고 source의 실제 값과 provenance를 다시 대조한다.

반례 반례에서는 `기간·timezone·status는 명시한 학습 가정이다` 상태인데도 Green을 주장하게 된다.

❌ DISTINCT 없이 고객 중복을 그대로 둔다

왜 틀리나 비정본 Q38 두 기간 교집합 SQL의 grain·owner·관찰·경계 중 적어도 하나를 건너뛴다.

바르게 읽기 INTERSECT로 공통 customer_id를 구한다. 그리고 source의 실제 값과 provenance를 다시 대조한다.

반례 반례에서는 `여러 거래를 고객 중복 행으로 내지 않는다` 상태인데도 Green을 주장하게 된다.

❌ account_id를 customer_id처럼 비교한다

왜 틀리나 비정본 Q38 두 기간 교집합 SQL의 grain·owner·관찰·경계 중 적어도 하나를 건너뛴다.

바르게 읽기 customer를 JOIN하고 stable order로 출력한다. 그리고 source의 실제 값과 provenance를 다시 대조한다.

반례 반례에서는 `fixture 예상은 실제 query 실행 결과가 아니다` 상태인데도 Green을 주장하게 된다.

❌ Q38 fixture 예상을 운영 DB 결과로 부른다

왜 틀리나 비정본 Q38 두 기간 교집합 SQL의 grain·owner·관찰·경계 중 적어도 하나를 건너뛴다.

바르게 읽기 customer를 JOIN하고 stable order로 출력한다. 그리고 source의 실제 값과 provenance를 다시 대조한다.

반례 반례에서는 `workbook 제공 정답이 아니다` 상태인데도 Green을 주장하게 된다.

11

STEP 11 / 13

이 코드가 보장하지 않는 것

이 코드가 책임지지 않는 일을 분리합니다.

직접 미보장

workbook 제공 정답이 아니다

이 책임을 맡는 곳: metric/query grain
직접 미보장

기간·timezone·status는 명시한 학습 가정이다

이 책임을 맡는 곳: 별도 local/external 실행
직접 미보장

여러 거래를 고객 중복 행으로 내지 않는다

이 책임을 맡는 곳: secret·개인정보·운영 정책
직접 미보장

fixture 예상은 실제 query 실행 결과가 아니다

이 책임을 맡는 곳: infrastructure·사람 검토
12

STEP 12 / 13

직접 다시 써보기

뜻 → 조각 → 전체 코드 순서로 다시 씁니다.

1단계 · 뜻부터 복원

다음 역할을 고정값과 미보장 경계까지 말한다: 두 반개구간 모두에서 성공 거래가 있는 고객을 DISTINCT와 INTERSECT로 한 번만 반환하는 비정본 Q38 예시다.

2단계 · 코드 조각 재조립

  1. 원문 1–10줄
  2. 원문 11–20줄
  3. 원문 21–30줄
  4. 원문 31–32줄

3단계 · 파일 전체 다시 쓰기

32개 물리 줄을 원본 순서로 복원하고 SHA-256 272af1c9a1014ea94ed5071c2015154c1f25ded763bd4b9d6f2c0a8816c2f8fe와 대조한다.

자가 점검
  • 원본 source/template bytes와 줄 번호를 바꾸지 않았는가?
  • 정본 3개와 학습용 예시 8개를 구분했는가?
  • RequestId local Gate와 DB wait local drill의 Green 범위를 분리했는가?
  • dashboard·alert·incident timeline을 NOT_RUN_EXTERNAL 또는 사람 검토로 남겼는가?
  • Q37의 JOIN grain과 Q38의 SUCCESS·반개구간 가정을 드러냈는가?
13

STEP 13 / 13

전체 원본 source

감사로 고정한 전체 source를 가감 없이 확인합니다.

학습용 예시 전체 확인하기 · 정본 답안 아님
학습용 예시 · Q37/Q38 prompt 기반 SQL · 정본 답안 아님illustrative/sql/W23-SQL-Q38.sqlSHA-256 272af1c9a1014ea94ed5071c2015154c1f25ded763bd4b9d6f2c0a8816c2f8fe
W23-SQL-Q38 — 두 반개구간 모두 거래한 고객을 INTERSECT로 찾기 전체
-- 학습용 예시 · 정본 답안 아님
-- 가정: 거래는 status='SUCCESS'이며 두 기간은 [start, end) 반개구간이다.
-- 입력 grain: business_tx 1행/거래. 출력 grain: customer 1행.

WITH period_a AS (
    SELECT DISTINCT a.customer_id
    FROM business_tx AS tx
    JOIN account AS a ON a.account_id = tx.account_id
    WHERE tx.status = 'SUCCESS'
      AND tx.occurred_at >= TIMESTAMPTZ '2026-06-30 00:00:00+09'
      AND tx.occurred_at <  TIMESTAMPTZ '2026-07-03 00:00:00+09'
),
period_b AS (
    SELECT DISTINCT a.customer_id
    FROM business_tx AS tx
    JOIN account AS a ON a.account_id = tx.account_id
    WHERE tx.status = 'SUCCESS'
      AND tx.occurred_at >= TIMESTAMPTZ '2026-12-28 00:00:00+09'
      AND tx.occurred_at <  TIMESTAMPTZ '2027-01-03 00:00:00+09'
),
both_periods AS (
    SELECT customer_id FROM period_a
    INTERSECT
    SELECT customer_id FROM period_b
)
SELECT c.customer_id, c.customer_name
FROM both_periods AS b
JOIN customer AS c ON c.customer_id = b.customer_id
ORDER BY c.customer_id;

-- workbook fixture 예상: customer_id=1, 김민수 한 행.
-- DISTINCT/INTERSECT가 없으면 같은 고객의 여러 거래 때문에 중복될 수 있다.
10

D6 runbooks index — DB timeout과 ledger mismatch의 멈춤·확인·escalation 순서

illustrative/markdown/W23-D6-runbooks-index.md

학습용 예시 · alert/runbook template · 정본 답안 아님 · 외부 미실행 · 학습용 예시 · 정본 답안 아님 · W23-F10
16줄 연결16줄 번역2 chunks
01

STEP 01 / 13

오늘 이 코드에서 해결할 문제

무엇을 이해해야 하는지 질문부터 잡습니다.

오늘의 한 문장

DB timeout과 ledger mismatch의 증상 보존·금지 행동·진단 순서·완화·검증·timeline을 분리한 D6 학습 runbook index다.

  1. `DB timeout`은 어느 줄에서 생기거나 검증될까?
  2. 입력→guard→관찰→cleanup 또는 stable output 순서는 무엇인가?
  3. local 자동 owner와 external human owner는 각각 누구인가?
  4. 이 source가 직접 관찰하지 않은 Green은 무엇인가?
  5. 반례는 `외부 fault injection을 수행한 증거가 아니다` 경계와 어떻게 연결되는가?
이 파일에서 끝까지 다시 쓰는 값DB timeoutLedger mismatchrequestIdmismatch=0HUMAN_SEMANTIC_REVIEW_REQUIRED
02

STEP 02 / 13

아주 짧게: 이 코드는 왜 필요할까?

웹소설 대신 이 코드가 필요한 이유만 두 문단으로 쉽게 봅니다.

STARRY가 metric catalog·requestId 봉투·DB wait 영수증·alert/runbook·SQL grain 표를 서로 다른 칸에 놓는다.

D6 runbooks index — DB timeout과 ledger mismatch의 멈춤·확인·escalation 순서 ― 관측 증거 흐름으로 바꾸기

DB timeout과 ledger mismatch의 증상 보존·금지 행동·진단 순서·완화·검증·timeline을 분리한 D6 학습 runbook index다.

핵심값 DB timeout, Ledger mismatch, requestId, mismatch=0, HUMAN_SEMANTIC_REVIEW_REQUIRED을 원본 줄로 따라가되, `외부 fault injection을 수행한 증거가 아니다`까지 함께 표시해 local 관찰을 외부 운영 Green으로 부풀리지 않는다.

딱 여기까지만 비유는 grain·owner·순서를 기억하게 할 뿐 실제 Gradle/Docker/PostgreSQL 실행, dashboard·notification, 운영 SLA를 자동 증명하지 않는다.

03

STEP 03 / 13

초등학생도 이해하는 설명

생활 비유와 실제 코드의 경계를 함께 확인합니다.

원문 1–10줄

1~10줄을 한 덩어리로 읽어 1번째 움직임을 본다. DB timeout과 ledger mismatch의 증상 보존·금지 행동·진단 순서·완화·검증·timeline을 분리한 D6 학습 runbook index다.

코드 연결
1~10줄
비유
DB가 느릴 때와 장부가 어긋날 때 서로 다른 비상 카드를 꺼내, 먼저 피해를 멈추고 좁은 범위에서 확인한 뒤 담당 승인으로 복구하는 안내판
비유의 끝
외부 fault injection을 수행한 증거가 아니다

원문 11–19줄

11~19줄을 한 덩어리로 읽어 2번째 움직임을 본다. DB timeout과 ledger mismatch의 증상 보존·금지 행동·진단 순서·완화·검증·timeline을 분리한 D6 학습 runbook index다.

코드 연결
11~19줄
비유
DB가 느릴 때와 장부가 어긋날 때 서로 다른 비상 카드를 꺼내, 먼저 피해를 멈추고 좁은 범위에서 확인한 뒤 담당 승인으로 복구하는 안내판
비유의 끝
무제한 retry나 즉시 balance UPDATE를 금지한다
문제의 첫 장면히토리 → 니지카 → 료 → 키타
  1. 히토리

    첫 고정값은 `DB timeout` 맞아?

  2. 니지카

    DB timeout과 ledger mismatch의 증상 보존·금지 행동·진단 순서·완화·검증·timeline을 분리한 D6 학습 runbook index다.

  3. 원문에서 `DB timeout`이 만들어지거나 확인되는 줄을 찾자.

  4. 키타

    그리고 `외부 fault injection을 수행한 증거가 아니다`도 같이 적어.

입력에서 결과까지히토리 → 니지카 → 료 → 키타
  1. 히토리

    `Ledger mismatch`은 언제 생겨?

  2. 니지카

    증상·영향·requestId 또는 mismatch row를 보존한다. → 무제한 retry·자동 재처리를 멈춘다.

  3. 정해진 순서로 진단하고 승인된 조치만 한다. → wait=0 또는 mismatch=0과 timeline을 남긴다.

  4. 키타

    관찰값과 `무제한 retry나 즉시 balance UPDATE를 금지한다`을 분리하면 돼.

04

STEP 04 / 13

비유 ↔ 코드 전체 연결표

감사 규칙상 연결 대상인 원본 16줄을 빠짐없이 연결합니다.

단어 몇 개만 뽑은 표가 아닙니다.학습용 예시 · alert/runbook template · 정본 답안 아님 · 외부 미실행에서 비어 있지 않은 모든 줄을 원본 줄 번호 그대로 연결했습니다.16 / 16 연결
정확한 원본 줄STARRY 비유실제 뜻·입력·결과·한계
1줄F10-L01 # W23 incident runbook index - 학습용 예시 DB가 느릴 때와 장부가 어긋날 때 서로 다른 비상 카드를 꺼내, 먼저 피해를 멈추고 좁은 범위에서 확인한 뒤 담당 승인으로 복구하는 안내판 이 source의 provenance·grain·가정·반례·실행 경계를 사람이 확인할 설명 줄이다.
입력
requestId/DB wait 또는 mismatch/ledger evidence와 승인 owner
결과·효과
이 줄 뒤에는 항목 전체의 `DB timeout` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
외부 fault injection을 수행한 증거가 아니다
3줄F10-L03 ## DB timeout DB가 느릴 때와 장부가 어긋날 때 서로 다른 비상 카드를 꺼내, 먼저 피해를 멈추고 좁은 범위에서 확인한 뒤 담당 승인으로 복구하는 안내판 이 source의 provenance·grain·가정·반례·실행 경계를 사람이 확인할 설명 줄이다.
입력
requestId/DB wait 또는 mismatch/ledger evidence와 승인 owner
결과·효과
이 줄 뒤에는 항목 전체의 `requestId` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
correction은 finance 승인이 필요하다
4줄F10-L04 1. 증상과 고객 영향, 최초 requestId와 발생시각을 보존한다. DB가 느릴 때와 장부가 어긋날 때 서로 다른 비상 카드를 꺼내, 먼저 피해를 멈추고 좁은 범위에서 확인한 뒤 담당 승인으로 복구하는 안내판 비정본 incident runbook index의 4번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
입력
requestId/DB wait 또는 mismatch/ledger evidence와 승인 owner
결과·효과
이 줄 뒤에는 항목 전체의 `mismatch=0` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
실제 incident timeline은 사람이 검토해야 한다
5줄F10-L05 2. 무제한 retry와 자동 재처리를 중지한다. DB가 느릴 때와 장부가 어긋날 때 서로 다른 비상 카드를 꺼내, 먼저 피해를 멈추고 좁은 범위에서 확인한 뒤 담당 승인으로 복구하는 안내판 비정본 incident runbook index의 5번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
입력
requestId/DB wait 또는 mismatch/ledger evidence와 승인 owner
결과·효과
이 줄 뒤에는 항목 전체의 `HUMAN_SEMANTIC_REVIEW_REQUIRED` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
외부 fault injection을 수행한 증거가 아니다
6줄F10-L06 3. readiness -> pool pending -> network -> PostgreSQL wait 순서로 확인한다. DB가 느릴 때와 장부가 어긋날 때 서로 다른 비상 카드를 꺼내, 먼저 피해를 멈추고 좁은 범위에서 확인한 뒤 담당 승인으로 복구하는 안내판 비정본 incident runbook index의 6번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
입력
requestId/DB wait 또는 mismatch/ledger evidence와 승인 owner
결과·효과
이 줄 뒤에는 항목 전체의 `DB timeout` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
무제한 retry나 즉시 balance UPDATE를 금지한다
7줄F10-L07 4. 승인된 범위에서만 timeout 완화 또는 traffic 축소를 수행한다. DB가 느릴 때와 장부가 어긋날 때 서로 다른 비상 카드를 꺼내, 먼저 피해를 멈추고 좁은 범위에서 확인한 뒤 담당 승인으로 복구하는 안내판 비정본 incident runbook index의 7번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
입력
requestId/DB wait 또는 mismatch/ledger evidence와 승인 owner
결과·효과
이 줄 뒤에는 항목 전체의 `Ledger mismatch` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
correction은 finance 승인이 필요하다
8줄F10-L08 5. API sample과 DB wait=0을 함께 확인한다. DB가 느릴 때와 장부가 어긋날 때 서로 다른 비상 카드를 꺼내, 먼저 피해를 멈추고 좁은 범위에서 확인한 뒤 담당 승인으로 복구하는 안내판 비정본 incident runbook index에서 `5. API sample과 DB wait=0을 함께 확인한다.` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
requestId/DB wait 또는 mismatch/ledger evidence와 승인 owner
결과·효과
이 줄 뒤에는 항목 전체의 `requestId` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
실제 incident timeline은 사람이 검토해야 한다
9줄F10-L09 6. rollback 기준, escalation owner, 명령 결과와 timeline을 남긴다. DB가 느릴 때와 장부가 어긋날 때 서로 다른 비상 카드를 꺼내, 먼저 피해를 멈추고 좁은 범위에서 확인한 뒤 담당 승인으로 복구하는 안내판 비정본 incident runbook index의 9번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
입력
requestId/DB wait 또는 mismatch/ledger evidence와 승인 owner
결과·효과
이 줄 뒤에는 항목 전체의 `mismatch=0` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
외부 fault injection을 수행한 증거가 아니다
11줄F10-L11 ## Ledger mismatch DB가 느릴 때와 장부가 어긋날 때 서로 다른 비상 카드를 꺼내, 먼저 피해를 멈추고 좁은 범위에서 확인한 뒤 담당 승인으로 복구하는 안내판 이 source의 provenance·grain·가정·반례·실행 경계를 사람이 확인할 설명 줄이다.
입력
requestId/DB wait 또는 mismatch/ledger evidence와 승인 owner
결과·효과
이 줄 뒤에는 항목 전체의 `DB timeout` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
correction은 finance 승인이 필요하다
12줄F10-L12 1. mismatch row와 영향 계좌를 격리하고 원본 evidence를 보존한다. DB가 느릴 때와 장부가 어긋날 때 서로 다른 비상 카드를 꺼내, 먼저 피해를 멈추고 좁은 범위에서 확인한 뒤 담당 승인으로 복구하는 안내판 비정본 incident runbook index의 12번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
입력
requestId/DB wait 또는 mismatch/ledger evidence와 승인 owner
결과·효과
이 줄 뒤에는 항목 전체의 `Ledger mismatch` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
실제 incident timeline은 사람이 검토해야 한다
13줄F10-L13 2. balance를 즉시 UPDATE하거나 자동 재처리하지 않는다. DB가 느릴 때와 장부가 어긋날 때 서로 다른 비상 카드를 꺼내, 먼저 피해를 멈추고 좁은 범위에서 확인한 뒤 담당 승인으로 복구하는 안내판 비정본 incident runbook index의 13번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
입력
requestId/DB wait 또는 mismatch/ledger evidence와 승인 owner
결과·효과
이 줄 뒤에는 항목 전체의 `requestId` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
외부 fault injection을 수행한 증거가 아니다
14줄F10-L14 3. ledger pair, business_tx, idempotency state, source event를 대조한다. DB가 느릴 때와 장부가 어긋날 때 서로 다른 비상 카드를 꺼내, 먼저 피해를 멈추고 좁은 범위에서 확인한 뒤 담당 승인으로 복구하는 안내판 비정본 incident runbook index의 14번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
입력
requestId/DB wait 또는 mismatch/ledger evidence와 승인 owner
결과·효과
이 줄 뒤에는 항목 전체의 `mismatch=0` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
무제한 retry나 즉시 balance UPDATE를 금지한다
15줄F10-L15 4. finance 승인 뒤 correction entry만 추가한다. DB가 느릴 때와 장부가 어긋날 때 서로 다른 비상 카드를 꺼내, 먼저 피해를 멈추고 좁은 범위에서 확인한 뒤 담당 승인으로 복구하는 안내판 비정본 incident runbook index의 15번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
입력
requestId/DB wait 또는 mismatch/ledger evidence와 승인 owner
결과·효과
이 줄 뒤에는 항목 전체의 `HUMAN_SEMANTIC_REVIEW_REQUIRED` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
correction은 finance 승인이 필요하다
16줄F10-L16 5. 대사 mismatch=0과 고객 응답을 다시 확인한다. DB가 느릴 때와 장부가 어긋날 때 서로 다른 비상 카드를 꺼내, 먼저 피해를 멈추고 좁은 범위에서 확인한 뒤 담당 승인으로 복구하는 안내판 비정본 incident runbook index에서 `5. 대사 mismatch=0과 고객 응답을 다시 확인한다.` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
requestId/DB wait 또는 mismatch/ledger evidence와 승인 owner
결과·효과
이 줄 뒤에는 항목 전체의 `DB timeout` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
실제 incident timeline은 사람이 검토해야 한다
17줄F10-L17 6. 승인자, correction 근거, rollback 및 후속조치를 기록한다. DB가 느릴 때와 장부가 어긋날 때 서로 다른 비상 카드를 꺼내, 먼저 피해를 멈추고 좁은 범위에서 확인한 뒤 담당 승인으로 복구하는 안내판 비정본 incident runbook index의 17번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
입력
requestId/DB wait 또는 mismatch/ledger evidence와 승인 owner
결과·효과
이 줄 뒤에는 항목 전체의 `Ledger mismatch` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
외부 fault injection을 수행한 증거가 아니다
19줄F10-L19 외부 fault injection과 incident timeline이 없으면 `HUMAN_SEMANTIC_REVIEW_REQUIRED`다. DB가 느릴 때와 장부가 어긋날 때 서로 다른 비상 카드를 꺼내, 먼저 피해를 멈추고 좁은 범위에서 확인한 뒤 담당 승인으로 복구하는 안내판 fault injection과 incident timeline을 사람이 검토해야 closure되는 경계다.
입력
requestId/DB wait 또는 mismatch/ledger evidence와 승인 owner
결과·효과
이 줄 뒤에는 항목 전체의 `mismatch=0` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
correction은 finance 승인이 필요하다
Green 범위히토리 → 니지카 → 료 → 키타
  1. 히토리

    marker나 문서가 보이면 W23 전체 성공이야?

  2. 니지카

    아니. 이 source가 직접 검증한 claim만 말해야 해.

  3. 직접 연결되는 대표 값은 `HUMAN_SEMANTIC_REVIEW_REQUIRED`이야.

  4. 키타

    `correction은 finance 승인이 필요하다`는 별도 실행·사람 증거가 필요해.

05

STEP 05 / 13

원본 코드 조각

원본을 2개 의미 조각으로 나누어 그대로 확인합니다.

파일을 한꺼번에 외우지 않고 실행 의미가 이어지는 작은 조각으로 봅니다. 아래 코드는 prompt·fixture·가정을 밝힌 학습용 예시 source이며, 제공 정본 답안이 아닙니다.

F10-C01 · 원문 1–10줄1–10줄
1–10줄 원본
# W23 incident runbook index - 학습용 예시

## DB timeout
1. 증상과 고객 영향, 최초 requestId와 발생시각을 보존한다.
2. 무제한 retry와 자동 재처리를 중지한다.
3. readiness -> pool pending -> network -> PostgreSQL wait 순서로 확인한다.
4. 승인된 범위에서만 timeout 완화 또는 traffic 축소를 수행한다.
5. API sample과 DB wait=0을 함께 확인한다.
6. rollback 기준, escalation owner, 명령 결과와 timeline을 남긴다.
F10-C02 · 원문 11–19줄11–19줄
11–19줄 원본
## Ledger mismatch
1. mismatch row와 영향 계좌를 격리하고 원본 evidence를 보존한다.
2. balance를 즉시 UPDATE하거나 자동 재처리하지 않는다.
3. ledger pair, business_tx, idempotency state, source event를 대조한다.
4. finance 승인 뒤 correction entry만 추가한다.
5. 대사 mismatch=0과 고객 응답을 다시 확인한다.
6. 승인자, correction 근거, rollback 및 후속조치를 기록한다.

외부 fault injection과 incident timeline이 없으면 `HUMAN_SEMANTIC_REVIEW_REQUIRED`다.
06

STEP 06 / 13

코드 한 줄씩 한국어로 번역

비어 있지 않은 16줄을 모두 한국어로 옮깁니다.

전체 번역 16 / 16

비어 있지 않은 원본 줄은 하나도 생략하지 않습니다.

원본한국어 번역
1# W23 incident runbook index - 학습용 예시이 source의 provenance·grain·가정·반례·실행 경계를 사람이 확인할 설명 줄이다.
3## DB timeout이 source의 provenance·grain·가정·반례·실행 경계를 사람이 확인할 설명 줄이다.
41. 증상과 고객 영향, 최초 requestId와 발생시각을 보존한다.비정본 incident runbook index의 4번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
52. 무제한 retry와 자동 재처리를 중지한다.비정본 incident runbook index의 5번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
63. readiness -> pool pending -> network -> PostgreSQL wait 순서로 확인한다.비정본 incident runbook index의 6번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
74. 승인된 범위에서만 timeout 완화 또는 traffic 축소를 수행한다.비정본 incident runbook index의 7번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
85. API sample과 DB wait=0을 함께 확인한다.비정본 incident runbook index에서 `5. API sample과 DB wait=0을 함께 확인한다.` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
96. rollback 기준, escalation owner, 명령 결과와 timeline을 남긴다.비정본 incident runbook index의 9번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
11## Ledger mismatch이 source의 provenance·grain·가정·반례·실행 경계를 사람이 확인할 설명 줄이다.
121. mismatch row와 영향 계좌를 격리하고 원본 evidence를 보존한다.비정본 incident runbook index의 12번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
132. balance를 즉시 UPDATE하거나 자동 재처리하지 않는다.비정본 incident runbook index의 13번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
143. ledger pair, business_tx, idempotency state, source event를 대조한다.비정본 incident runbook index의 14번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
154. finance 승인 뒤 correction entry만 추가한다.비정본 incident runbook index의 15번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
165. 대사 mismatch=0과 고객 응답을 다시 확인한다.비정본 incident runbook index에서 `5. 대사 mismatch=0과 고객 응답을 다시 확인한다.` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
176. 승인자, correction 근거, rollback 및 후속조치를 기록한다.비정본 incident runbook index의 17번째 원문을 앞 입력과 뒤 관찰·책임 경계 사이에 연결한다.
19외부 fault injection과 incident timeline이 없으면 `HUMAN_SEMANTIC_REVIEW_REQUIRED`다.fault injection과 incident timeline을 사람이 검토해야 closure되는 경계다.
07

STEP 07 / 13

기존 수준의 한 줄 읽기·문법 해부

쉬운 설명 다음에 문법과 실행 순서를 정밀하게 읽습니다.

한 줄로 읽기

DB timeout과 ledger mismatch의 증상 보존·금지 행동·진단 순서·완화·검증·timeline을 분리한 D6 학습 runbook index다. 다만 외부 fault injection을 수행한 증거가 아니다

문법 해부

  • 두 `##` heading이 DB timeout과 Ledger mismatch의 서로 다른 대응 책임을 분리한다. 이 D6 index는 F04의 root incident-runbook.md와 별도 학습 파일이다.
  • 각 번호 목록은 preserve/stop→diagnose→approved action→verify→record 순서로 읽는다. validator의 shape/hash PASS는 절차 의미 PASS가 아니다.

실행 순서

  1. 증상·영향·requestId 또는 mismatch row를 보존한다.
  2. 무제한 retry·자동 재처리를 멈춘다.
  3. 정해진 순서로 진단하고 승인된 조치만 한다.
  4. wait=0 또는 mismatch=0과 timeline을 남긴다.

W23 조각별 정밀 해설

F10-C01 · 원문 1–10줄
문법 해부
1~10줄의 `원문 1–10줄`을 입력·grain/guard·관찰·cleanup/stable output 단계로 나눈다.
실제 값 추적
항목 전체 흐름에 연결해 `DB timeout`을 대조한다. 이 값이 chunk 단독 산출이라는 뜻은 아니다.
정상 예
정상 예에서는 source 순서와 owner 계약이 일치해 `DB timeout`을 관찰한다.
틀린 예·반례
반례에서는 선행 guard·grain·stable order·cleanup을 생략한다. 동결 경계: 외부 fault injection을 수행한 증거가 아니다.
착각 방지
`원문 1–10줄`이 항목 전체 또는 외부 운영 Green을 단독 증명한다고 읽지 않는다.
하지 않는 일
이 chunk가 책임지지 않는 범위: 외부 fault injection을 수행한 증거가 아니다.
다음 연결
다음 source chunk의 입력 또는 exact local marker·SQL oracle·사람 검토 경계로 결과를 넘긴다.
F10-C02 · 원문 11–19줄
문법 해부
11~19줄의 `원문 11–19줄`을 입력·grain/guard·관찰·cleanup/stable output 단계로 나눈다.
실제 값 추적
항목 전체 흐름에 연결해 `Ledger mismatch`을 대조한다. 이 값이 chunk 단독 산출이라는 뜻은 아니다.
정상 예
정상 예에서는 source 순서와 owner 계약이 일치해 `Ledger mismatch`을 관찰한다.
틀린 예·반례
반례에서는 선행 guard·grain·stable order·cleanup을 생략한다. 동결 경계: 무제한 retry나 즉시 balance UPDATE를 금지한다.
착각 방지
`원문 11–19줄`이 항목 전체 또는 외부 운영 Green을 단독 증명한다고 읽지 않는다.
하지 않는 일
이 chunk가 책임지지 않는 범위: 무제한 retry나 즉시 balance UPDATE를 금지한다.
다음 연결
다음 source chunk의 입력 또는 exact local marker·SQL oracle·사람 검토 경계로 결과를 넘긴다.
반례히토리 → 니지카 → 료 → 키타
  1. 히토리

    겉보기에는 맞지만 깨지는 예는?

  2. 니지카

    timeout이면 즉시 retry 횟수를 무제한으로 늘린다

  3. 그 상태는 입력 grain·owner·관찰 중 한 칸이 비어 있어.

  4. 키타

    수정한 뒤 같은 source bytes와 evidence를 다시 대조해.

08

STEP 08 / 13

실제 값 따라가기

같은 입력값이 어느 줄을 지나 어떤 결과가 되는지 추적합니다.

순서들어온 값코드가 하는 일나온 값·상태경계
F10-T01 DB timeoutrequestId+timereadiness→pool→network→waitnarrow cause무제한 retry 금지
F10-T02 ledgermismatch rowsledger/tx/idempotency/source 대조approved correction직접 UPDATE 금지
F10-T03 closureAPI+DB or reconciliationdouble checktimelinefault injection 미실행
책임 경계히토리 → 니지카 → 료 → 키타
  1. 히토리

    이 항목의 마지막 책임선은?

  2. 니지카

    직접 역할은 `비정본 incident runbook index`이야.

  3. 대표 경계는 `실제 incident timeline은 사람이 검토해야 한다`이야.

  4. 키타

    정본/학습용 label과 local/external owner까지 확인하면 끝이야.

09

STEP 09 / 13

Micrometer·RequestId·PowerShell·PostgreSQL 내부에서 벌어지는 일

Micrometer·JUnit·PowerShell·PostgreSQL·alert/runbook에서 실제로 일어나는 일과 증명 범위를 구분합니다.

triage

고객 영향과 증거를 먼저 보존한다.

원인 확정 전 임의 수정은 금지한다.
mitigation

승인된 범위의 traffic 축소·correction entry를 사용한다.

운영 권한과 승인자는 별도다.
validator/review

heading·단계 수·hash 같은 shape를 자동 대조한다.

root runbook과 D6 index는 distinct이며 절차의 안전성·timeline은 사람 검토가 남는다.
10

STEP 10 / 13

흔한 착각과 틀린 예

그럴듯하지만 틀린 해석을 반례로 고칩니다.

❌ timeout이면 즉시 retry 횟수를 무제한으로 늘린다

왜 틀리나 비정본 incident runbook index의 grain·owner·관찰·경계 중 적어도 하나를 건너뛴다.

바르게 읽기 증상·영향·requestId 또는 mismatch row를 보존한다. 그리고 source의 실제 값과 provenance를 다시 대조한다.

반례 반례에서는 `외부 fault injection을 수행한 증거가 아니다` 상태인데도 Green을 주장하게 된다.

❌ pool pending을 곧바로 DB row lock이라고 부른다

왜 틀리나 비정본 incident runbook index의 grain·owner·관찰·경계 중 적어도 하나를 건너뛴다.

바르게 읽기 무제한 retry·자동 재처리를 멈춘다. 그리고 source의 실제 값과 provenance를 다시 대조한다.

반례 반례에서는 `무제한 retry나 즉시 balance UPDATE를 금지한다` 상태인데도 Green을 주장하게 된다.

❌ mismatch balance를 직접 UPDATE한다

왜 틀리나 비정본 incident runbook index의 grain·owner·관찰·경계 중 적어도 하나를 건너뛴다.

바르게 읽기 정해진 순서로 진단하고 승인된 조치만 한다. 그리고 source의 실제 값과 provenance를 다시 대조한다.

반례 반례에서는 `correction은 finance 승인이 필요하다` 상태인데도 Green을 주장하게 된다.

❌ 승인 전 자동 재처리한다

왜 틀리나 비정본 incident runbook index의 grain·owner·관찰·경계 중 적어도 하나를 건너뛴다.

바르게 읽기 wait=0 또는 mismatch=0과 timeline을 남긴다. 그리고 source의 실제 값과 provenance를 다시 대조한다.

반례 반례에서는 `실제 incident timeline은 사람이 검토해야 한다` 상태인데도 Green을 주장하게 된다.

❌ index 문서를 실제 incident timeline이라 부른다

왜 틀리나 비정본 incident runbook index의 grain·owner·관찰·경계 중 적어도 하나를 건너뛴다.

바르게 읽기 wait=0 또는 mismatch=0과 timeline을 남긴다. 그리고 source의 실제 값과 provenance를 다시 대조한다.

반례 반례에서는 `외부 fault injection을 수행한 증거가 아니다` 상태인데도 Green을 주장하게 된다.

11

STEP 11 / 13

이 코드가 보장하지 않는 것

이 코드가 책임지지 않는 일을 분리합니다.

직접 미보장

외부 fault injection을 수행한 증거가 아니다

이 책임을 맡는 곳: metric/query grain
직접 미보장

무제한 retry나 즉시 balance UPDATE를 금지한다

이 책임을 맡는 곳: 별도 local/external 실행
직접 미보장

correction은 finance 승인이 필요하다

이 책임을 맡는 곳: secret·개인정보·운영 정책
직접 미보장

실제 incident timeline은 사람이 검토해야 한다

이 책임을 맡는 곳: infrastructure·사람 검토
12

STEP 12 / 13

직접 다시 써보기

뜻 → 조각 → 전체 코드 순서로 다시 씁니다.

1단계 · 뜻부터 복원

다음 역할을 고정값과 미보장 경계까지 말한다: DB timeout과 ledger mismatch의 증상 보존·금지 행동·진단 순서·완화·검증·timeline을 분리한 D6 학습 runbook index다.

2단계 · 코드 조각 재조립

  1. 원문 1–10줄
  2. 원문 11–19줄

3단계 · 파일 전체 다시 쓰기

19개 물리 줄을 원본 순서로 복원하고 SHA-256 a48ebc06c4d61f6904fc29e7a837645fda0d08a2aac00b97157ee0ac5c83b076와 대조한다.

자가 점검
  • 원본 source/template bytes와 줄 번호를 바꾸지 않았는가?
  • 정본 3개와 학습용 예시 8개를 구분했는가?
  • RequestId local Gate와 DB wait local drill의 Green 범위를 분리했는가?
  • dashboard·alert·incident timeline을 NOT_RUN_EXTERNAL 또는 사람 검토로 남겼는가?
  • Q37의 JOIN grain과 Q38의 SUCCESS·반개구간 가정을 드러냈는가?
13

STEP 13 / 13

전체 원본 source

감사로 고정한 전체 source를 가감 없이 확인합니다.

학습용 예시 전체 확인하기 · 정본 답안 아님
학습용 예시 · alert/runbook template · 정본 답안 아님 · 외부 미실행illustrative/markdown/W23-D6-runbooks-index.mdSHA-256 a48ebc06c4d61f6904fc29e7a837645fda0d08a2aac00b97157ee0ac5c83b076
D6 runbooks index — DB timeout과 ledger mismatch의 멈춤·확인·escalation 순서 전체
# W23 incident runbook index - 학습용 예시

## DB timeout
1. 증상과 고객 영향, 최초 requestId와 발생시각을 보존한다.
2. 무제한 retry와 자동 재처리를 중지한다.
3. readiness -> pool pending -> network -> PostgreSQL wait 순서로 확인한다.
4. 승인된 범위에서만 timeout 완화 또는 traffic 축소를 수행한다.
5. API sample과 DB wait=0을 함께 확인한다.
6. rollback 기준, escalation owner, 명령 결과와 timeline을 남긴다.

## Ledger mismatch
1. mismatch row와 영향 계좌를 격리하고 원본 evidence를 보존한다.
2. balance를 즉시 UPDATE하거나 자동 재처리하지 않는다.
3. ledger pair, business_tx, idempotency state, source event를 대조한다.
4. finance 승인 뒤 correction entry만 추가한다.
5. 대사 mismatch=0과 고객 응답을 다시 확인한다.
6. 승인자, correction 근거, rollback 및 후속조치를 기록한다.

외부 fault injection과 incident timeline이 없으면 `HUMAN_SEMANTIC_REVIEW_REQUIRED`다.
11

D7 claim registry — local 자동 증거와 external 수동 증거를 합산하지 않는 장부

illustrative/json/W23-D7-claim-registry.json

학습용 예시 · claim registry · 정본 답안 아님 · 비실행 · 학습용 예시 · 정본 답안 아님 · W23-F11
31줄 연결31줄 번역4 chunks
01

STEP 01 / 13

오늘 이 코드에서 해결할 문제

무엇을 이해해야 하는지 질문부터 잡습니다.

오늘의 한 문장

local requestId·DB wait와 외부 dashboard·alert evidence를 서로 다른 status로 분리하는 D7 claim registry 예시다.

  1. `VERIFIABLE_LOCAL`은 어느 줄에서 생기거나 검증될까?
  2. 입력→guard→관찰→cleanup 또는 stable output 순서는 무엇인가?
  3. local 자동 owner와 external human owner는 각각 누구인가?
  4. 이 source가 직접 관찰하지 않은 Green은 무엇인가?
  5. 반례는 `illustrative registry 자체가 실행 evidence가 아니다` 경계와 어떻게 연결되는가?
이 파일에서 끝까지 다시 쓰는 값VERIFIABLE_LOCALNOT_RUN_EXTERNALMANUAL_REVIEW_REQUIREDobserved=1 cleared=0local!=external
02

STEP 02 / 13

아주 짧게: 이 코드는 왜 필요할까?

웹소설 대신 이 코드가 필요한 이유만 두 문단으로 쉽게 봅니다.

STARRY가 metric catalog·requestId 봉투·DB wait 영수증·alert/runbook·SQL grain 표를 서로 다른 칸에 놓는다.

D7 claim registry — local 자동 증거와 external 수동 증거를 합산하지 않는 장부 ― 관측 증거 흐름으로 바꾸기

local requestId·DB wait와 외부 dashboard·alert evidence를 서로 다른 status로 분리하는 D7 claim registry 예시다.

핵심값 VERIFIABLE_LOCAL, NOT_RUN_EXTERNAL, MANUAL_REVIEW_REQUIRED, observed=1 cleared=0, local!=external을 원본 줄로 따라가되, `illustrative registry 자체가 실행 evidence가 아니다`까지 함께 표시해 local 관찰을 외부 운영 Green으로 부풀리지 않는다.

딱 여기까지만 비유는 grain·owner·순서를 기억하게 할 뿐 실제 Gradle/Docker/PostgreSQL 실행, dashboard·notification, 운영 SLA를 자동 증명하지 않는다.

03

STEP 03 / 13

초등학생도 이해하는 설명

생활 비유와 실제 코드의 경계를 함께 확인합니다.

원문 1–10줄

1~10줄을 한 덩어리로 읽어 1번째 움직임을 본다. local requestId·DB wait와 외부 dashboard·alert evidence를 서로 다른 status로 분리하는 D7 claim registry 예시다.

코드 연결
1~10줄
비유
자동 검표기가 확인한 두 칸과 아직 현장 담당자가 채워야 할 두 칸을 색깔별로 나눠, 빈 칸을 합계로 숨기지 않는 증거 장부
비유의 끝
illustrative registry 자체가 실행 evidence가 아니다

원문 11–20줄

11~20줄을 한 덩어리로 읽어 2번째 움직임을 본다. local requestId·DB wait와 외부 dashboard·alert evidence를 서로 다른 status로 분리하는 D7 claim registry 예시다.

코드 연결
11~20줄
비유
자동 검표기가 확인한 두 칸과 아직 현장 담당자가 채워야 할 두 칸을 색깔별로 나눠, 빈 칸을 합계로 숨기지 않는 증거 장부
비유의 끝
local Gate와 외부 수동 evidence를 합산하지 않는다

원문 21–30줄

21~30줄을 한 덩어리로 읽어 3번째 움직임을 본다. local requestId·DB wait와 외부 dashboard·alert evidence를 서로 다른 status로 분리하는 D7 claim registry 예시다.

코드 연결
21~30줄
비유
자동 검표기가 확인한 두 칸과 아직 현장 담당자가 채워야 할 두 칸을 색깔별로 나눠, 빈 칸을 합계로 숨기지 않는 증거 장부
비유의 끝
URL·시각·screenshot hash가 필요하다
문제의 첫 장면히토리 → 니지카 → 료 → 키타
  1. 히토리

    첫 고정값은 `VERIFIABLE_LOCAL` 맞아?

  2. 니지카

    local requestId·DB wait와 외부 dashboard·alert evidence를 서로 다른 status로 분리하는 D7 claim registry 예시다.

  3. 원문에서 `VERIFIABLE_LOCAL`이 만들어지거나 확인되는 줄을 찾자.

  4. 키타

    그리고 `illustrative registry 자체가 실행 evidence가 아니다`도 같이 적어.

입력에서 결과까지히토리 → 니지카 → 료 → 키타
  1. 히토리

    `NOT_RUN_EXTERNAL`은 언제 생겨?

  2. 니지카

    requestId Gate의 selector·test 수·runbook hash를 묶는다. → DB wait의 1→0·value 2·cleanup 1을 묶는다.

  3. dashboard 미실행을 null field로 드러낸다. → alert 사람 검토가 남았음을 별도 claim으로 둔다.

  4. 키타

    관찰값과 `local Gate와 외부 수동 evidence를 합산하지 않는다`을 분리하면 돼.

04

STEP 04 / 13

비유 ↔ 코드 전체 연결표

감사 규칙상 연결 대상인 원본 31줄을 빠짐없이 연결합니다.

단어 몇 개만 뽑은 표가 아닙니다.학습용 예시 · claim registry · 정본 답안 아님 · 비실행에서 비어 있지 않은 모든 줄을 원본 줄 번호 그대로 연결했습니다.31 / 31 연결
정확한 원본 줄STARRY 비유실제 뜻·입력·결과·한계
1줄F11-L01 { 자동 검표기가 확인한 두 칸과 아직 현장 담당자가 채워야 할 두 칸을 색깔별로 나눠, 빈 칸을 합계로 숨기지 않는 증거 장부 현재 object·array·block 또는 query 범위를 열거나 닫아 구조와 실행 순서를 유지한다.
입력
gate.json·db-wait.json local 값과 external URL/time/screenshot 상태
결과·효과
이 줄 뒤에는 항목 전체의 `VERIFIABLE_LOCAL` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
illustrative registry 자체가 실행 evidence가 아니다
2줄F11-L02 "classification": "ILLUSTRATIVE_NOT_CANONICAL", 자동 검표기가 확인한 두 칸과 아직 현장 담당자가 채워야 할 두 칸을 색깔별로 나눠, 빈 칸을 합계로 숨기지 않는 증거 장부 비정본 local/external claim 분리 registry에서 `"classification": "ILLUSTRATIVE_NOT_CANONICAL",` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
gate.json·db-wait.json local 값과 external URL/time/screenshot 상태
결과·효과
이 줄 뒤에는 항목 전체의 `NOT_RUN_EXTERNAL` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
local Gate와 외부 수동 evidence를 합산하지 않는다
3줄F11-L03 "week": 23, 자동 검표기가 확인한 두 칸과 아직 현장 담당자가 채워야 할 두 칸을 색깔별로 나눠, 빈 칸을 합계로 숨기지 않는 증거 장부 비정본 local/external claim 분리 registry에서 `"week": 23,` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
gate.json·db-wait.json local 값과 external URL/time/screenshot 상태
결과·효과
이 줄 뒤에는 항목 전체의 `MANUAL_REVIEW_REQUIRED` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
URL·시각·screenshot hash가 필요하다
4줄F11-L04 "local_request_id_gate": { 자동 검표기가 확인한 두 칸과 아직 현장 담당자가 채워야 할 두 칸을 색깔별로 나눠, 빈 칸을 합계로 숨기지 않는 증거 장부 비정본 local/external claim 분리 registry에서 `"local_request_id_gate": {` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
gate.json·db-wait.json local 값과 external URL/time/screenshot 상태
결과·효과
이 줄 뒤에는 항목 전체의 `observed=1 cleared=0` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
사람 검토 전 외부 Green이 아니다
5줄F11-L05 "status": "VERIFIABLE_LOCAL", 자동 검표기가 확인한 두 칸과 아직 현장 담당자가 채워야 할 두 칸을 색깔별로 나눠, 빈 칸을 합계로 숨기지 않는 증거 장부 정본 runner로 로컬에서 검증 가능한 claim임을 나타내며 실행 완료 PASS와는 다르다.
입력
gate.json·db-wait.json local 값과 external URL/time/screenshot 상태
결과·효과
이 줄 뒤에는 항목 전체의 `local!=external` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
illustrative registry 자체가 실행 evidence가 아니다
6줄F11-L06 "selector": "com.example.financialcore.api.RequestIdFilterTest", 자동 검표기가 확인한 두 칸과 아직 현장 담당자가 채워야 할 두 칸을 색깔별로 나눠, 빈 칸을 합계로 숨기지 않는 증거 장부 W23 Gate가 정확히 선택하는 requestId regression class 이름을 고정한다.
입력
gate.json·db-wait.json local 값과 external URL/time/screenshot 상태
결과·효과
이 줄 뒤에는 항목 전체의 `VERIFIABLE_LOCAL` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
local Gate와 외부 수동 evidence를 합산하지 않는다
7줄F11-L07 "tests": 2, 자동 검표기가 확인한 두 칸과 아직 현장 담당자가 채워야 할 두 칸을 색깔별로 나눠, 빈 칸을 합계로 숨기지 않는 증거 장부 비정본 local/external claim 분리 registry에서 `"tests": 2,` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
gate.json·db-wait.json local 값과 external URL/time/screenshot 상태
결과·효과
이 줄 뒤에는 항목 전체의 `NOT_RUN_EXTERNAL` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
URL·시각·screenshot hash가 필요하다
8줄F11-L08 "runbook_sha256": "FROM_GATE_JSON" 자동 검표기가 확인한 두 칸과 아직 현장 담당자가 채워야 할 두 칸을 색깔별로 나눠, 빈 칸을 합계로 숨기지 않는 증거 장부 현재 runbook bytes의 SHA-256을 evidence에 결박한다.
입력
gate.json·db-wait.json local 값과 external URL/time/screenshot 상태
결과·효과
이 줄 뒤에는 항목 전체의 `MANUAL_REVIEW_REQUIRED` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
사람 검토 전 외부 Green이 아니다
9줄F11-L09 }, 자동 검표기가 확인한 두 칸과 아직 현장 담당자가 채워야 할 두 칸을 색깔별로 나눠, 빈 칸을 합계로 숨기지 않는 증거 장부 현재 object·array·block 또는 query 범위를 열거나 닫아 구조와 실행 순서를 유지한다.
입력
gate.json·db-wait.json local 값과 external URL/time/screenshot 상태
결과·효과
이 줄 뒤에는 항목 전체의 `observed=1 cleared=0` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
illustrative registry 자체가 실행 evidence가 아니다
10줄F11-L10 "db_wait_drill": { 자동 검표기가 확인한 두 칸과 아직 현장 담당자가 채워야 할 두 칸을 색깔별로 나눠, 빈 칸을 합계로 숨기지 않는 증거 장부 비정본 local/external claim 분리 registry에서 `"db_wait_drill": {` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
gate.json·db-wait.json local 값과 external URL/time/screenshot 상태
결과·효과
이 줄 뒤에는 항목 전체의 `local!=external` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
local Gate와 외부 수동 evidence를 합산하지 않는다
11줄F11-L11 "status": "VERIFIABLE_LOCAL", 자동 검표기가 확인한 두 칸과 아직 현장 담당자가 채워야 할 두 칸을 색깔별로 나눠, 빈 칸을 합계로 숨기지 않는 증거 장부 정본 runner로 로컬에서 검증 가능한 claim임을 나타내며 실행 완료 PASS와는 다르다.
입력
gate.json·db-wait.json local 값과 external URL/time/screenshot 상태
결과·효과
이 줄 뒤에는 항목 전체의 `VERIFIABLE_LOCAL` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
URL·시각·screenshot hash가 필요하다
12줄F11-L12 "scope": "ROW_UPDATE", 자동 검표기가 확인한 두 칸과 아직 현장 담당자가 채워야 할 두 칸을 색깔별로 나눠, 빈 칸을 합계로 숨기지 않는 증거 장부 비정본 local/external claim 분리 registry에서 `"scope": "ROW_UPDATE",` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
gate.json·db-wait.json local 값과 external URL/time/screenshot 상태
결과·효과
이 줄 뒤에는 항목 전체의 `NOT_RUN_EXTERNAL` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
사람 검토 전 외부 Green이 아니다
13줄F11-L13 "observed": 1, 자동 검표기가 확인한 두 칸과 아직 현장 담당자가 채워야 할 두 칸을 색깔별로 나눠, 빈 칸을 합계로 숨기지 않는 증거 장부 DB wait snapshot에서 기대하는 관찰값 1을 claim에 연결한다.
입력
gate.json·db-wait.json local 값과 external URL/time/screenshot 상태
결과·효과
이 줄 뒤에는 항목 전체의 `MANUAL_REVIEW_REQUIRED` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
illustrative registry 자체가 실행 evidence가 아니다
14줄F11-L14 "cleared": 0, 자동 검표기가 확인한 두 칸과 아직 현장 담당자가 채워야 할 두 칸을 색깔별로 나눠, 빈 칸을 합계로 숨기지 않는 증거 장부 holder·waiter 종료 뒤 남은 Lock wait가 0이어야 함을 claim에 연결한다.
입력
gate.json·db-wait.json local 값과 external URL/time/screenshot 상태
결과·효과
이 줄 뒤에는 항목 전체의 `observed=1 cleared=0` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
local Gate와 외부 수동 evidence를 합산하지 않는다
15줄F11-L15 "final_value": 2, 자동 검표기가 확인한 두 칸과 아직 현장 담당자가 채워야 할 두 칸을 색깔별로 나눠, 빈 칸을 합계로 숨기지 않는 증거 장부 두 row UPDATE의 최종 fixture 값이 2여야 함을 claim에 연결한다.
입력
gate.json·db-wait.json local 값과 external URL/time/screenshot 상태
결과·효과
이 줄 뒤에는 항목 전체의 `local!=external` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
URL·시각·screenshot hash가 필요하다
16줄F11-L16 "cleanup": 1 자동 검표기가 확인한 두 칸과 아직 현장 담당자가 채워야 할 두 칸을 색깔별로 나눠, 빈 칸을 합계로 숨기지 않는 증거 장부 소유한 disposable resource cleanup 확인값 1을 claim에 연결한다.
입력
gate.json·db-wait.json local 값과 external URL/time/screenshot 상태
결과·효과
이 줄 뒤에는 항목 전체의 `VERIFIABLE_LOCAL` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
사람 검토 전 외부 Green이 아니다
17줄F11-L17 }, 자동 검표기가 확인한 두 칸과 아직 현장 담당자가 채워야 할 두 칸을 색깔별로 나눠, 빈 칸을 합계로 숨기지 않는 증거 장부 현재 object·array·block 또는 query 범위를 열거나 닫아 구조와 실행 순서를 유지한다.
입력
gate.json·db-wait.json local 값과 external URL/time/screenshot 상태
결과·효과
이 줄 뒤에는 항목 전체의 `NOT_RUN_EXTERNAL` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
illustrative registry 자체가 실행 evidence가 아니다
18줄F11-L18 "dashboard": { 자동 검표기가 확인한 두 칸과 아직 현장 담당자가 채워야 할 두 칸을 색깔별로 나눠, 빈 칸을 합계로 숨기지 않는 증거 장부 비정본 local/external claim 분리 registry에서 `"dashboard": {` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
gate.json·db-wait.json local 값과 external URL/time/screenshot 상태
결과·효과
이 줄 뒤에는 항목 전체의 `MANUAL_REVIEW_REQUIRED` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
local Gate와 외부 수동 evidence를 합산하지 않는다
19줄F11-L19 "status": "NOT_RUN_EXTERNAL", 자동 검표기가 확인한 두 칸과 아직 현장 담당자가 채워야 할 두 칸을 색깔별로 나눠, 빈 칸을 합계로 숨기지 않는 증거 장부 URL·관찰시각·screenshot hash가 없어 외부 실행을 아직 주장하지 않는 정확한 상태다.
입력
gate.json·db-wait.json local 값과 external URL/time/screenshot 상태
결과·효과
이 줄 뒤에는 항목 전체의 `observed=1 cleared=0` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
URL·시각·screenshot hash가 필요하다
20줄F11-L20 "url": null, 자동 검표기가 확인한 두 칸과 아직 현장 담당자가 채워야 할 두 칸을 색깔별로 나눠, 빈 칸을 합계로 숨기지 않는 증거 장부 비정본 local/external claim 분리 registry에서 `"url": null,` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
gate.json·db-wait.json local 값과 external URL/time/screenshot 상태
결과·효과
이 줄 뒤에는 항목 전체의 `local!=external` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
사람 검토 전 외부 Green이 아니다
21줄F11-L21 "observed_at": null, 자동 검표기가 확인한 두 칸과 아직 현장 담당자가 채워야 할 두 칸을 색깔별로 나눠, 빈 칸을 합계로 숨기지 않는 증거 장부 비정본 local/external claim 분리 registry에서 `"observed_at": null,` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
gate.json·db-wait.json local 값과 external URL/time/screenshot 상태
결과·효과
이 줄 뒤에는 항목 전체의 `VERIFIABLE_LOCAL` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
illustrative registry 자체가 실행 evidence가 아니다
22줄F11-L22 "screenshot_sha256": null 자동 검표기가 확인한 두 칸과 아직 현장 담당자가 채워야 할 두 칸을 색깔별로 나눠, 빈 칸을 합계로 숨기지 않는 증거 장부 비정본 local/external claim 분리 registry에서 `"screenshot_sha256": null` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
gate.json·db-wait.json local 값과 external URL/time/screenshot 상태
결과·효과
이 줄 뒤에는 항목 전체의 `NOT_RUN_EXTERNAL` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
local Gate와 외부 수동 evidence를 합산하지 않는다
23줄F11-L23 }, 자동 검표기가 확인한 두 칸과 아직 현장 담당자가 채워야 할 두 칸을 색깔별로 나눠, 빈 칸을 합계로 숨기지 않는 증거 장부 현재 object·array·block 또는 query 범위를 열거나 닫아 구조와 실행 순서를 유지한다.
입력
gate.json·db-wait.json local 값과 external URL/time/screenshot 상태
결과·효과
이 줄 뒤에는 항목 전체의 `MANUAL_REVIEW_REQUIRED` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
URL·시각·screenshot hash가 필요하다
24줄F11-L24 "alert_notification": { 자동 검표기가 확인한 두 칸과 아직 현장 담당자가 채워야 할 두 칸을 색깔별로 나눠, 빈 칸을 합계로 숨기지 않는 증거 장부 비정본 local/external claim 분리 registry에서 `"alert_notification": {` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
gate.json·db-wait.json local 값과 external URL/time/screenshot 상태
결과·효과
이 줄 뒤에는 항목 전체의 `observed=1 cleared=0` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
사람 검토 전 외부 Green이 아니다
25줄F11-L25 "status": "MANUAL_REVIEW_REQUIRED", 자동 검표기가 확인한 두 칸과 아직 현장 담당자가 채워야 할 두 칸을 색깔별로 나눠, 빈 칸을 합계로 숨기지 않는 증거 장부 자동 local 검증과 별도로 사람의 dashboard·notification 의미 검토가 남았음을 표시한다.
입력
gate.json·db-wait.json local 값과 external URL/time/screenshot 상태
결과·효과
이 줄 뒤에는 항목 전체의 `local!=external` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
illustrative registry 자체가 실행 evidence가 아니다
26줄F11-L26 "url": null, 자동 검표기가 확인한 두 칸과 아직 현장 담당자가 채워야 할 두 칸을 색깔별로 나눠, 빈 칸을 합계로 숨기지 않는 증거 장부 비정본 local/external claim 분리 registry에서 `"url": null,` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
gate.json·db-wait.json local 값과 external URL/time/screenshot 상태
결과·효과
이 줄 뒤에는 항목 전체의 `VERIFIABLE_LOCAL` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
local Gate와 외부 수동 evidence를 합산하지 않는다
27줄F11-L27 "observed_at": null, 자동 검표기가 확인한 두 칸과 아직 현장 담당자가 채워야 할 두 칸을 색깔별로 나눠, 빈 칸을 합계로 숨기지 않는 증거 장부 비정본 local/external claim 분리 registry에서 `"observed_at": null,` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
gate.json·db-wait.json local 값과 external URL/time/screenshot 상태
결과·효과
이 줄 뒤에는 항목 전체의 `NOT_RUN_EXTERNAL` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
URL·시각·screenshot hash가 필요하다
28줄F11-L28 "screenshot_sha256": null 자동 검표기가 확인한 두 칸과 아직 현장 담당자가 채워야 할 두 칸을 색깔별로 나눠, 빈 칸을 합계로 숨기지 않는 증거 장부 비정본 local/external claim 분리 registry에서 `"screenshot_sha256": null` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
gate.json·db-wait.json local 값과 external URL/time/screenshot 상태
결과·효과
이 줄 뒤에는 항목 전체의 `MANUAL_REVIEW_REQUIRED` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
사람 검토 전 외부 Green이 아니다
29줄F11-L29 }, 자동 검표기가 확인한 두 칸과 아직 현장 담당자가 채워야 할 두 칸을 색깔별로 나눠, 빈 칸을 합계로 숨기지 않는 증거 장부 현재 object·array·block 또는 query 범위를 열거나 닫아 구조와 실행 순서를 유지한다.
입력
gate.json·db-wait.json local 값과 external URL/time/screenshot 상태
결과·효과
이 줄 뒤에는 항목 전체의 `observed=1 cleared=0` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
illustrative registry 자체가 실행 evidence가 아니다
30줄F11-L30 "boundary": "local Gate와 외부 수동 evidence를 합산하지 않는다" 자동 검표기가 확인한 두 칸과 아직 현장 담당자가 채워야 할 두 칸을 색깔별로 나눠, 빈 칸을 합계로 숨기지 않는 증거 장부 비정본 local/external claim 분리 registry에서 `"boundary": "local Gate와 외부 수동 evidence를 합산하지 않는` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
입력
gate.json·db-wait.json local 값과 external URL/time/screenshot 상태
결과·효과
이 줄 뒤에는 항목 전체의 `local!=external` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
local Gate와 외부 수동 evidence를 합산하지 않는다
31줄F11-L31 } 자동 검표기가 확인한 두 칸과 아직 현장 담당자가 채워야 할 두 칸을 색깔별로 나눠, 빈 칸을 합계로 숨기지 않는 증거 장부 현재 object·array·block 또는 query 범위를 열거나 닫아 구조와 실행 순서를 유지한다.
입력
gate.json·db-wait.json local 값과 external URL/time/screenshot 상태
결과·효과
이 줄 뒤에는 항목 전체의 `VERIFIABLE_LOCAL` 대조에 필요한 중간 상태가 생긴다. 이 한 줄만으로 Green이 되지는 않는다.
비유의 한계
URL·시각·screenshot hash가 필요하다
Green 범위히토리 → 니지카 → 료 → 키타
  1. 히토리

    marker나 문서가 보이면 W23 전체 성공이야?

  2. 니지카

    아니. 이 source가 직접 검증한 claim만 말해야 해.

  3. 직접 연결되는 대표 값은 `local!=external`이야.

  4. 키타

    `URL·시각·screenshot hash가 필요하다`는 별도 실행·사람 증거가 필요해.

05

STEP 05 / 13

원본 코드 조각

원본을 4개 의미 조각으로 나누어 그대로 확인합니다.

파일을 한꺼번에 외우지 않고 실행 의미가 이어지는 작은 조각으로 봅니다. 아래 코드는 prompt·fixture·가정을 밝힌 학습용 예시 source이며, 제공 정본 답안이 아닙니다.

F11-C01 · 원문 1–10줄1–10줄
1–10줄 원본
{
  "classification": "ILLUSTRATIVE_NOT_CANONICAL",
  "week": 23,
  "local_request_id_gate": {
    "status": "VERIFIABLE_LOCAL",
    "selector": "com.example.financialcore.api.RequestIdFilterTest",
    "tests": 2,
    "runbook_sha256": "FROM_GATE_JSON"
  },
  "db_wait_drill": {
F11-C02 · 원문 11–20줄11–20줄
11–20줄 원본
    "status": "VERIFIABLE_LOCAL",
    "scope": "ROW_UPDATE",
    "observed": 1,
    "cleared": 0,
    "final_value": 2,
    "cleanup": 1
  },
  "dashboard": {
    "status": "NOT_RUN_EXTERNAL",
    "url": null,
F11-C03 · 원문 21–30줄21–30줄
21–30줄 원본
    "observed_at": null,
    "screenshot_sha256": null
  },
  "alert_notification": {
    "status": "MANUAL_REVIEW_REQUIRED",
    "url": null,
    "observed_at": null,
    "screenshot_sha256": null
  },
  "boundary": "local Gate와 외부 수동 evidence를 합산하지 않는다"
F11-C04 · 원문 31–31줄31–31줄
31–31줄 원본
}
06

STEP 06 / 13

코드 한 줄씩 한국어로 번역

비어 있지 않은 31줄을 모두 한국어로 옮깁니다.

전체 번역 31 / 31

비어 있지 않은 원본 줄은 하나도 생략하지 않습니다.

원본한국어 번역
1{현재 object·array·block 또는 query 범위를 열거나 닫아 구조와 실행 순서를 유지한다.
2 "classification": "ILLUSTRATIVE_NOT_CANONICAL",비정본 local/external claim 분리 registry에서 `"classification": "ILLUSTRATIVE_NOT_CANONICAL",` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
3 "week": 23,비정본 local/external claim 분리 registry에서 `"week": 23,` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
4 "local_request_id_gate": {비정본 local/external claim 분리 registry에서 `"local_request_id_gate": {` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
5 "status": "VERIFIABLE_LOCAL",정본 runner로 로컬에서 검증 가능한 claim임을 나타내며 실행 완료 PASS와는 다르다.
6 "selector": "com.example.financialcore.api.RequestIdFilterTest",W23 Gate가 정확히 선택하는 requestId regression class 이름을 고정한다.
7 "tests": 2,비정본 local/external claim 분리 registry에서 `"tests": 2,` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
8 "runbook_sha256": "FROM_GATE_JSON"현재 runbook bytes의 SHA-256을 evidence에 결박한다.
9 },현재 object·array·block 또는 query 범위를 열거나 닫아 구조와 실행 순서를 유지한다.
10 "db_wait_drill": {비정본 local/external claim 분리 registry에서 `"db_wait_drill": {` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
11 "status": "VERIFIABLE_LOCAL",정본 runner로 로컬에서 검증 가능한 claim임을 나타내며 실행 완료 PASS와는 다르다.
12 "scope": "ROW_UPDATE",비정본 local/external claim 분리 registry에서 `"scope": "ROW_UPDATE",` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
13 "observed": 1,DB wait snapshot에서 기대하는 관찰값 1을 claim에 연결한다.
14 "cleared": 0,holder·waiter 종료 뒤 남은 Lock wait가 0이어야 함을 claim에 연결한다.
15 "final_value": 2,두 row UPDATE의 최종 fixture 값이 2여야 함을 claim에 연결한다.
16 "cleanup": 1소유한 disposable resource cleanup 확인값 1을 claim에 연결한다.
17 },현재 object·array·block 또는 query 범위를 열거나 닫아 구조와 실행 순서를 유지한다.
18 "dashboard": {비정본 local/external claim 분리 registry에서 `"dashboard": {` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
19 "status": "NOT_RUN_EXTERNAL",URL·관찰시각·screenshot hash가 없어 외부 실행을 아직 주장하지 않는 정확한 상태다.
20 "url": null,비정본 local/external claim 분리 registry에서 `"url": null,` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
21 "observed_at": null,비정본 local/external claim 분리 registry에서 `"observed_at": null,` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
22 "screenshot_sha256": null비정본 local/external claim 분리 registry에서 `"screenshot_sha256": null` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
23 },현재 object·array·block 또는 query 범위를 열거나 닫아 구조와 실행 순서를 유지한다.
24 "alert_notification": {비정본 local/external claim 분리 registry에서 `"alert_notification": {` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
25 "status": "MANUAL_REVIEW_REQUIRED",자동 local 검증과 별도로 사람의 dashboard·notification 의미 검토가 남았음을 표시한다.
26 "url": null,비정본 local/external claim 분리 registry에서 `"url": null,` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
27 "observed_at": null,비정본 local/external claim 분리 registry에서 `"observed_at": null,` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
28 "screenshot_sha256": null비정본 local/external claim 분리 registry에서 `"screenshot_sha256": null` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
29 },현재 object·array·block 또는 query 범위를 열거나 닫아 구조와 실행 순서를 유지한다.
30 "boundary": "local Gate와 외부 수동 evidence를 합산하지 않는다"비정본 local/external claim 분리 registry에서 `"boundary": "local Gate와 외부 수동 evidence를 합산하지 않는` field·값 또는 assignment를 다음 guard·관찰 단계로 전달한다.
31}현재 object·array·block 또는 query 범위를 열거나 닫아 구조와 실행 순서를 유지한다.
07

STEP 07 / 13

기존 수준의 한 줄 읽기·문법 해부

쉬운 설명 다음에 문법과 실행 순서를 정밀하게 읽습니다.

한 줄로 읽기

local requestId·DB wait와 외부 dashboard·alert evidence를 서로 다른 status로 분리하는 D7 claim registry 예시다. 다만 illustrative registry 자체가 실행 evidence가 아니다

문법 해부

  • JSON top-level 항목마다 claim owner와 status를 따로 둔다.
  • `VERIFIABLE_LOCAL`, `NOT_RUN_EXTERNAL`, `MANUAL_REVIEW_REQUIRED`를 서로 다른 상태로 유지한다.

실행 순서

  1. requestId Gate의 selector·test 수·runbook hash를 묶는다.
  2. DB wait의 1→0·value 2·cleanup 1을 묶는다.
  3. dashboard 미실행을 null field로 드러낸다.
  4. alert 사람 검토가 남았음을 별도 claim으로 둔다.

W23 조각별 정밀 해설

F11-C01 · 원문 1–10줄
문법 해부
1~10줄의 `원문 1–10줄`을 입력·grain/guard·관찰·cleanup/stable output 단계로 나눈다.
실제 값 추적
항목 전체 흐름에 연결해 `VERIFIABLE_LOCAL`을 대조한다. 이 값이 chunk 단독 산출이라는 뜻은 아니다.
정상 예
정상 예에서는 source 순서와 owner 계약이 일치해 `VERIFIABLE_LOCAL`을 관찰한다.
틀린 예·반례
반례에서는 선행 guard·grain·stable order·cleanup을 생략한다. 동결 경계: illustrative registry 자체가 실행 evidence가 아니다.
착각 방지
`원문 1–10줄`이 항목 전체 또는 외부 운영 Green을 단독 증명한다고 읽지 않는다.
하지 않는 일
이 chunk가 책임지지 않는 범위: illustrative registry 자체가 실행 evidence가 아니다.
다음 연결
다음 source chunk의 입력 또는 exact local marker·SQL oracle·사람 검토 경계로 결과를 넘긴다.
F11-C02 · 원문 11–20줄
문법 해부
11~20줄의 `원문 11–20줄`을 입력·grain/guard·관찰·cleanup/stable output 단계로 나눈다.
실제 값 추적
항목 전체 흐름에 연결해 `NOT_RUN_EXTERNAL`을 대조한다. 이 값이 chunk 단독 산출이라는 뜻은 아니다.
정상 예
정상 예에서는 source 순서와 owner 계약이 일치해 `NOT_RUN_EXTERNAL`을 관찰한다.
틀린 예·반례
반례에서는 선행 guard·grain·stable order·cleanup을 생략한다. 동결 경계: local Gate와 외부 수동 evidence를 합산하지 않는다.
착각 방지
`원문 11–20줄`이 항목 전체 또는 외부 운영 Green을 단독 증명한다고 읽지 않는다.
하지 않는 일
이 chunk가 책임지지 않는 범위: local Gate와 외부 수동 evidence를 합산하지 않는다.
다음 연결
다음 source chunk의 입력 또는 exact local marker·SQL oracle·사람 검토 경계로 결과를 넘긴다.
F11-C03 · 원문 21–30줄
문법 해부
21~30줄의 `원문 21–30줄`을 입력·grain/guard·관찰·cleanup/stable output 단계로 나눈다.
실제 값 추적
항목 전체 흐름에 연결해 `MANUAL_REVIEW_REQUIRED`을 대조한다. 이 값이 chunk 단독 산출이라는 뜻은 아니다.
정상 예
정상 예에서는 source 순서와 owner 계약이 일치해 `MANUAL_REVIEW_REQUIRED`을 관찰한다.
틀린 예·반례
반례에서는 선행 guard·grain·stable order·cleanup을 생략한다. 동결 경계: URL·시각·screenshot hash가 필요하다.
착각 방지
`원문 21–30줄`이 항목 전체 또는 외부 운영 Green을 단독 증명한다고 읽지 않는다.
하지 않는 일
이 chunk가 책임지지 않는 범위: URL·시각·screenshot hash가 필요하다.
다음 연결
다음 source chunk의 입력 또는 exact local marker·SQL oracle·사람 검토 경계로 결과를 넘긴다.
F11-C04 · 원문 31–31줄
문법 해부
31~31줄의 `원문 31–31줄`을 입력·grain/guard·관찰·cleanup/stable output 단계로 나눈다.
실제 값 추적
항목 전체 흐름에 연결해 `observed=1 cleared=0`을 대조한다. 이 값이 chunk 단독 산출이라는 뜻은 아니다.
정상 예
정상 예에서는 source 순서와 owner 계약이 일치해 `observed=1 cleared=0`을 관찰한다.
틀린 예·반례
반례에서는 선행 guard·grain·stable order·cleanup을 생략한다. 동결 경계: 사람 검토 전 외부 Green이 아니다.
착각 방지
`원문 31–31줄`이 항목 전체 또는 외부 운영 Green을 단독 증명한다고 읽지 않는다.
하지 않는 일
이 chunk가 책임지지 않는 범위: 사람 검토 전 외부 Green이 아니다.
다음 연결
다음 source chunk의 입력 또는 exact local marker·SQL oracle·사람 검토 경계로 결과를 넘긴다.
반례히토리 → 니지카 → 료 → 키타
  1. 히토리

    겉보기에는 맞지만 깨지는 예는?

  2. 니지카

    VERIFIABLE_LOCAL을 실행 완료 PASS로 읽는다

  3. 그 상태는 입력 grain·owner·관찰 중 한 칸이 비어 있어.

  4. 키타

    수정한 뒤 같은 source bytes와 evidence를 다시 대조해.

08

STEP 08 / 13

실제 값 따라가기

같은 입력값이 어느 줄을 지나 어떤 결과가 되는지 추적합니다.

순서들어온 값코드가 하는 일나온 값·상태경계
F11-T01 local gateselector+hashautomaticVERIFIABLE_LOCAL실행 전에는 실제 PASS 아님
F11-T02 local DBrow wait valuesautomaticVERIFIABLE_LOCAL운영 DB 아님
F11-T03 externalURL/time/screenshotmanualNOT_RUN/MANUALlocal 값과 합산 금지
책임 경계히토리 → 니지카 → 료 → 키타
  1. 히토리

    이 항목의 마지막 책임선은?

  2. 니지카

    직접 역할은 `비정본 local/external claim 분리 registry`이야.

  3. 대표 경계는 `사람 검토 전 외부 Green이 아니다`이야.

  4. 키타

    정본/학습용 label과 local/external owner까지 확인하면 끝이야.

09

STEP 09 / 13

Micrometer·RequestId·PowerShell·PostgreSQL 내부에서 벌어지는 일

Micrometer·JUnit·PowerShell·PostgreSQL·alert/runbook에서 실제로 일어나는 일과 증명 범위를 구분합니다.

claim registry

어떤 증거가 어떤 결론을 소유하는지 구조화한다.

registry 자체가 source runner를 실행하지 않는다.
predecessor index

현재 predecessor가 gate.json만 index한다.

db-wait.json·dashboard·alert evidence까지 index됐다고 확대하면 안 된다.
human review

threshold·screenshot·timeline 의미를 사람이 확인한다.

형식 검사가 운영 의미를 대신하지 않는다.
10

STEP 10 / 13

흔한 착각과 틀린 예

그럴듯하지만 틀린 해석을 반례로 고칩니다.

❌ VERIFIABLE_LOCAL을 실행 완료 PASS로 읽는다

왜 틀리나 비정본 local/external claim 분리 registry의 grain·owner·관찰·경계 중 적어도 하나를 건너뛴다.

바르게 읽기 requestId Gate의 selector·test 수·runbook hash를 묶는다. 그리고 source의 실제 값과 provenance를 다시 대조한다.

반례 반례에서는 `illustrative registry 자체가 실행 evidence가 아니다` 상태인데도 Green을 주장하게 된다.

❌ predecessor gate.json index가 db-wait/external까지 포함한다고 본다

왜 틀리나 비정본 local/external claim 분리 registry의 grain·owner·관찰·경계 중 적어도 하나를 건너뛴다.

바르게 읽기 DB wait의 1→0·value 2·cleanup 1을 묶는다. 그리고 source의 실제 값과 provenance를 다시 대조한다.

반례 반례에서는 `local Gate와 외부 수동 evidence를 합산하지 않는다` 상태인데도 Green을 주장하게 된다.

❌ null URL을 예시 URL로 채워 통과시킨다

왜 틀리나 비정본 local/external claim 분리 registry의 grain·owner·관찰·경계 중 적어도 하나를 건너뛴다.

바르게 읽기 dashboard 미실행을 null field로 드러낸다. 그리고 source의 실제 값과 provenance를 다시 대조한다.

반례 반례에서는 `URL·시각·screenshot hash가 필요하다` 상태인데도 Green을 주장하게 된다.

❌ MANUAL_REVIEW_REQUIRED를 실패와 같은 뜻으로 본다

왜 틀리나 비정본 local/external claim 분리 registry의 grain·owner·관찰·경계 중 적어도 하나를 건너뛴다.

바르게 읽기 alert 사람 검토가 남았음을 별도 claim으로 둔다. 그리고 source의 실제 값과 provenance를 다시 대조한다.

반례 반례에서는 `사람 검토 전 외부 Green이 아니다` 상태인데도 Green을 주장하게 된다.

❌ claim registry 자체를 primary evidence producer라 부른다

왜 틀리나 비정본 local/external claim 분리 registry의 grain·owner·관찰·경계 중 적어도 하나를 건너뛴다.

바르게 읽기 alert 사람 검토가 남았음을 별도 claim으로 둔다. 그리고 source의 실제 값과 provenance를 다시 대조한다.

반례 반례에서는 `illustrative registry 자체가 실행 evidence가 아니다` 상태인데도 Green을 주장하게 된다.

11

STEP 11 / 13

이 코드가 보장하지 않는 것

이 코드가 책임지지 않는 일을 분리합니다.

직접 미보장

illustrative registry 자체가 실행 evidence가 아니다

이 책임을 맡는 곳: metric/query grain
직접 미보장

local Gate와 외부 수동 evidence를 합산하지 않는다

이 책임을 맡는 곳: 별도 local/external 실행
직접 미보장

URL·시각·screenshot hash가 필요하다

이 책임을 맡는 곳: secret·개인정보·운영 정책
직접 미보장

사람 검토 전 외부 Green이 아니다

이 책임을 맡는 곳: infrastructure·사람 검토
12

STEP 12 / 13

직접 다시 써보기

뜻 → 조각 → 전체 코드 순서로 다시 씁니다.

1단계 · 뜻부터 복원

다음 역할을 고정값과 미보장 경계까지 말한다: local requestId·DB wait와 외부 dashboard·alert evidence를 서로 다른 status로 분리하는 D7 claim registry 예시다.

2단계 · 코드 조각 재조립

  1. 원문 1–10줄
  2. 원문 11–20줄
  3. 원문 21–30줄
  4. 원문 31–31줄

3단계 · 파일 전체 다시 쓰기

31개 물리 줄을 원본 순서로 복원하고 SHA-256 38e00eda0957286b254161c8cc830631f2111be6068400dcde8e83447f1f0aec와 대조한다.

자가 점검
  • 원본 source/template bytes와 줄 번호를 바꾸지 않았는가?
  • 정본 3개와 학습용 예시 8개를 구분했는가?
  • RequestId local Gate와 DB wait local drill의 Green 범위를 분리했는가?
  • dashboard·alert·incident timeline을 NOT_RUN_EXTERNAL 또는 사람 검토로 남겼는가?
  • Q37의 JOIN grain과 Q38의 SUCCESS·반개구간 가정을 드러냈는가?
13

STEP 13 / 13

전체 원본 source

감사로 고정한 전체 source를 가감 없이 확인합니다.

학습용 예시 전체 확인하기 · 정본 답안 아님
학습용 예시 · claim registry · 정본 답안 아님 · 비실행illustrative/json/W23-D7-claim-registry.jsonSHA-256 38e00eda0957286b254161c8cc830631f2111be6068400dcde8e83447f1f0aec
D7 claim registry — local 자동 증거와 external 수동 증거를 합산하지 않는 장부 전체
{
  "classification": "ILLUSTRATIVE_NOT_CANONICAL",
  "week": 23,
  "local_request_id_gate": {
    "status": "VERIFIABLE_LOCAL",
    "selector": "com.example.financialcore.api.RequestIdFilterTest",
    "tests": 2,
    "runbook_sha256": "FROM_GATE_JSON"
  },
  "db_wait_drill": {
    "status": "VERIFIABLE_LOCAL",
    "scope": "ROW_UPDATE",
    "observed": 1,
    "cleared": 0,
    "final_value": 2,
    "cleanup": 1
  },
  "dashboard": {
    "status": "NOT_RUN_EXTERNAL",
    "url": null,
    "observed_at": null,
    "screenshot_sha256": null
  },
  "alert_notification": {
    "status": "MANUAL_REVIEW_REQUIRED",
    "url": null,
    "observed_at": null,
    "screenshot_sha256": null
  },
  "boundary": "local Gate와 외부 수동 evidence를 합산하지 않는다"
}