W22 · CI·AWS 최소 배포
22주차 코드 뒤풀이: 외부 CI·OIDC 증거부터 disposable restore·비용 teardown까지
유일한 정본 packaged source인 run-w22-restore.ps1과 외부 GitHub/AWS contract·template을 출처 등급별로 분리해 읽습니다. 외부 미실행은 NOT_RUN_EXTERNAL, 사람 검토 전 상태는 MANUAL_REVIEW_REQUIRED로 남기고, 로컬 restore만 3·120·0과 cleanup을 자동 검증합니다. D7 worksheet의 checked_at 누락 충돌과 prompt-only Q35·Q36의 비정본 가정도 그대로 드러냅니다.
01외부 CI 계약 — clean runner와 실패 artifact는 공식 run으로만 증명
illustrative/text/W22-D1-external-ci-contract.txt
학습용 예시 · PDF contract/template · 정본 답안 아님 · 학습용 예시 · 정본 답안 아님 · W22-F0111줄 연결11줄 번역2 chunks
외부 CI 계약 — clean runner와 실패 artifact는 공식 run으로만 증명
illustrative/text/W22-D1-external-ci-contract.txt
학습용 예시 · PDF contract/template · 정본 답안 아님 · 학습용 예시 · 정본 답안 아님 · W22-F01STEP 01 / 13
오늘 이 코드에서 해결할 문제
무엇을 이해해야 하는지 질문부터 잡습니다.
GitHub Actions의 공식 run URL·commit·실패 report artifact를 사람 검토에 묶고 로컬 Green을 금지하는 외부 실행 계약이다.
- `FUTURE_TRIGGER`은 어느 줄에서 생길까?
- 입력→guard→관찰→cleanup 순서는 무엇인가?
- local owner와 external human review는 누구인가?
- 직접 관찰하지 않은 Green은 무엇인가?
- 반례는 `실제 GitHub run이 아니다`이라는 경계와 어떻게 연결되는가?
FUTURE_TRIGGERNOT_RUN_EXTERNALofficial_run_urlartifact_urllocal_green_owner=noneSTEP 02 / 13
아주 짧게: 이 코드는 왜 필요할까?
웹소설 대신 이 코드가 필요한 이유만 두 문단으로 쉽게 봅니다.
STARRY가 GitHub run표·AWS 출입증·DB 복구 영수증·SQL 결과표를 서로 다른 칸에 놓는다.
외부 CI 계약 — clean runner와 실패 artifact는 공식 run으로만 증명 ― 증거 흐름으로 바꾸기
GitHub Actions의 공식 run URL·commit·실패 report artifact를 사람 검토에 묶고 로컬 Green을 금지하는 외부 실행 계약이다.
핵심값 FUTURE_TRIGGER, NOT_RUN_EXTERNAL, official_run_url, artifact_url, local_green_owner=none을 원본 줄로 따라가되, `실제 GitHub run이 아니다`까지 함께 표시해 Green 범위를 부풀리지 않는다.
딱 여기까지만 비유는 owner와 순서를 기억하게 할 뿐 외부 실행·AWS 계정 상태·PostgreSQL restore·SQL 결과를 자동 증명하지 않는다.
STEP 03 / 13
초등학생도 이해하는 설명
생활 비유와 실제 코드의 경계를 함께 확인합니다.
원문 1–10줄
1~10줄을 한 덩어리로 읽어 1번째 움직임을 본다. GitHub Actions의 공식 run URL·commit·실패 report artifact를 사람 검토에 묶고 로컬 Green을 금지하는 외부 실행 계약이다.
- 코드 연결
1~10줄- 비유
- 심판이 연습장 사진이 아니라 공식 경기 기록의 URL·선수 번호·영상 hash를 함께 대조하는 증거 봉투
- 비유의 끝
- 실제 GitHub run이 아니다
원문 11–11줄
11~11줄을 한 덩어리로 읽어 2번째 움직임을 본다. GitHub Actions의 공식 run URL·commit·실패 report artifact를 사람 검토에 묶고 로컬 Green을 금지하는 외부 실행 계약이다.
- 코드 연결
11~11줄- 비유
- 심판이 연습장 사진이 아니라 공식 경기 기록의 URL·선수 번호·영상 hash를 함께 대조하는 증거 봉투
- 비유의 끝
- 로컬 파일·문자열 검사는 외부 성공을 증명하지 않는다
문제의 첫 장면
-
첫 고정값은 `FUTURE_TRIGGER` 맞아?
-
GitHub Actions의 공식 run URL·commit·실패 report artifact를 사람 검토에 묶고 로컬 Green을 금지하는 외부 실행 계약이다.
-
원문에서 `FUTURE_TRIGGER`이 생기는 위치를 찾자.
-
그리고 `실제 GitHub run이 아니다`도 같이 적어.
입력에서 결과까지
-
`NOT_RUN_EXTERNAL`은 언제 생겨?
-
clean workflow를 작성한다. → push/PR로 공식 run을 만든다.
-
commit과 test summary·artifact를 묶는다. → 사람이 required check와 실패 artifact를 대조한다.
-
관찰값과 `로컬 파일·문자열 검사는 외부 성공을 증명하지 않는다`을 분리하면 돼.
STEP 04 / 13
비유 ↔ 코드 전체 연결표
감사 규칙상 연결 대상인 원본 11줄을 빠짐없이 연결합니다.
| 줄 | 정확한 원본 줄 | STARRY 비유 | 실제 뜻·입력·결과·한계 |
|---|---|---|---|
| 1줄F01-L01 | 학습용 예시 · PDF 외부 실행 계약 · 정본 답안 아님 |
심판이 연습장 사진이 아니라 공식 경기 기록의 URL·선수 번호·영상 hash를 함께 대조하는 증거 봉투 | 외부 GitHub Actions evidence 계약의 1번째 원문을 앞 guard와 뒤 관찰값 사이에 연결한다.
|
| 2줄F01-L02 | status: |
심판이 연습장 사진이 아니라 공식 경기 기록의 URL·선수 번호·영상 hash를 함께 대조하는 증거 봉투 | 외부 GitHub Actions evidence 계약에서 `status: FUTURE_TRIGGER` field·값 또는 assignment를 다음 단계에 전달한다.
|
| 3줄F01-L03 | execution: |
심판이 연습장 사진이 아니라 공식 경기 기록의 URL·선수 번호·영상 hash를 함께 대조하는 증거 봉투 | 실제 외부 실행을 아직 수행·증명하지 않았다는 상태를 명시한다.
|
| 4줄F01-L04 | required_fields: |
심판이 연습장 사진이 아니라 공식 경기 기록의 URL·선수 번호·영상 hash를 함께 대조하는 증거 봉투 | 공식 GitHub Actions run을 가리키는 URL field를 선언한다.
|
| 5줄F01-L05 | url_rule: |
심판이 연습장 사진이 아니라 공식 경기 기록의 URL·선수 번호·영상 hash를 함께 대조하는 증거 봉투 | 외부 GitHub Actions evidence 계약에서 `url_rule: official HTTPS GitHub Actions run URL` field·값 또는 assignment를 다음 단계에 전달한다.
|
| 6줄F01-L06 | hash_rule: |
심판이 연습장 사진이 아니라 공식 경기 기록의 URL·선수 번호·영상 hash를 함께 대조하는 증거 봉투 | 현재 file bytes를 64-hex SHA-256 값과 결박하는 field 또는 검사를 다룬다.
|
| 7줄F01-L07 | local_green_owner: |
심판이 연습장 사진이 아니라 공식 경기 기록의 URL·선수 번호·영상 hash를 함께 대조하는 증거 봉투 | 외부 GitHub Actions evidence 계약에서 `local_green_owner: none` field·값 또는 assignment를 다음 단계에 전달한다.
|
| 8줄F01-L08 | local_restore_owner: |
심판이 연습장 사진이 아니라 공식 경기 기록의 URL·선수 번호·영상 hash를 함께 대조하는 증거 봉투 | 외부 GitHub Actions evidence 계약에서 `local_restore_owner: scripts/run-w22-restore.ps1` field·값 또는 assignment를 다음 단계에 전달한다.
|
| 9줄F01-L09 | manual_rule: |
심판이 연습장 사진이 아니라 공식 경기 기록의 URL·선수 번호·영상 hash를 함께 대조하는 증거 봉투 | 외부 GitHub Actions evidence 계약에서 `manual_rule: 승인된 repository의 실제 push/PR 뒤 공식 run` field·값 또는 assignment를 다음 단계에 전달한다.
|
| 10줄F01-L10 | failure_artifact_rule: |
심판이 연습장 사진이 아니라 공식 경기 기록의 URL·선수 번호·영상 hash를 함께 대조하는 증거 봉투 | 외부 GitHub Actions evidence 계약에서 `failure_artifact_rule: 고의 실패 run에서도 test report ` field·값 또는 assignment를 다음 단계에 전달한다.
|
| 11줄F01-L11 | boundary: |
심판이 연습장 사진이 아니라 공식 경기 기록의 URL·선수 번호·영상 hash를 함께 대조하는 증거 봉투 | 외부 GitHub Actions evidence 계약에서 `boundary: 로컬 파일 존재·문자열 검사·self-declared PASS는 외부` field·값 또는 assignment를 다음 단계에 전달한다.
|
Green 범위
-
marker나 파일이 보이면 전부 성공이야?
-
아니. source가 직접 검증한 범위만 말해야 해.
-
직접 연결되는 대표 값은 `local_green_owner=none`이야.
-
`required check 설정은 사람이 확인한다`는 별도 증거가 필요해.
STEP 05 / 13
원본 코드 조각
원본을 2개 의미 조각으로 나누어 그대로 확인합니다.
파일을 한꺼번에 외우지 않고 실행 의미가 이어지는 작은 조각으로 봅니다. 아래 코드는 prompt·fixture·가정을 밝힌 학습용 예시 source이며, 제공 정본 답안이 아닙니다.
학습용 예시 · PDF 외부 실행 계약 · 정본 답안 아님
status: FUTURE_TRIGGER
execution: NOT_RUN_EXTERNAL
required_fields: official_run_url, run_id, commit_sha, workflow_name, conclusion, screenshot_path, screenshot_sha256, artifact_url
url_rule: official HTTPS GitHub Actions run URL
hash_rule: screenshot_sha256 is exact 64-hex hash of screenshot_path
local_green_owner: none
local_restore_owner: scripts/run-w22-restore.ps1 (Saturday)
manual_rule: 승인된 repository의 실제 push/PR 뒤 공식 run URL과 commit SHA를 사람이 대조한다.
failure_artifact_rule: 고의 실패 run에서도 test report artifact가 남아야 한다.
boundary: 로컬 파일 존재·문자열 검사·self-declared PASS는 외부 CI Green이 아니다.
STEP 06 / 13
코드 한 줄씩 한국어로 번역
비어 있지 않은 11줄을 모두 한국어로 옮깁니다.
비어 있지 않은 원본 줄은 하나도 생략하지 않습니다.
| 줄 | 원본 | 한국어 번역 |
|---|---|---|
| 1 | 학습용 예시 · PDF 외부 실행 계약 · 정본 답안 아님 | 외부 GitHub Actions evidence 계약의 1번째 원문을 앞 guard와 뒤 관찰값 사이에 연결한다. |
| 2 | status: FUTURE_TRIGGER | 외부 GitHub Actions evidence 계약에서 `status: FUTURE_TRIGGER` field·값 또는 assignment를 다음 단계에 전달한다. |
| 3 | execution: NOT_RUN_EXTERNAL | 실제 외부 실행을 아직 수행·증명하지 않았다는 상태를 명시한다. |
| 4 | required_fields: official_run_url, run_id, commit_sha, workflow_name, conclusion, screenshot_path, screenshot_sha256, artifact_url | 공식 GitHub Actions run을 가리키는 URL field를 선언한다. |
| 5 | url_rule: official HTTPS GitHub Actions run URL | 외부 GitHub Actions evidence 계약에서 `url_rule: official HTTPS GitHub Actions run URL` field·값 또는 assignment를 다음 단계에 전달한다. |
| 6 | hash_rule: screenshot_sha256 is exact 64-hex hash of screenshot_path | 현재 file bytes를 64-hex SHA-256 값과 결박하는 field 또는 검사를 다룬다. |
| 7 | local_green_owner: none | 외부 GitHub Actions evidence 계약에서 `local_green_owner: none` field·값 또는 assignment를 다음 단계에 전달한다. |
| 8 | local_restore_owner: scripts/run-w22-restore.ps1 (Saturday) | 외부 GitHub Actions evidence 계약에서 `local_restore_owner: scripts/run-w22-restore.ps1` field·값 또는 assignment를 다음 단계에 전달한다. |
| 9 | manual_rule: 승인된 repository의 실제 push/PR 뒤 공식 run URL과 commit SHA를 사람이 대조한다. | 외부 GitHub Actions evidence 계약에서 `manual_rule: 승인된 repository의 실제 push/PR 뒤 공식 run` field·값 또는 assignment를 다음 단계에 전달한다. |
| 10 | failure_artifact_rule: 고의 실패 run에서도 test report artifact가 남아야 한다. | 외부 GitHub Actions evidence 계약에서 `failure_artifact_rule: 고의 실패 run에서도 test report ` field·값 또는 assignment를 다음 단계에 전달한다. |
| 11 | boundary: 로컬 파일 존재·문자열 검사·self-declared PASS는 외부 CI Green이 아니다. | 외부 GitHub Actions evidence 계약에서 `boundary: 로컬 파일 존재·문자열 검사·self-declared PASS는 외부` field·값 또는 assignment를 다음 단계에 전달한다. |
STEP 07 / 13
기존 수준의 한 줄 읽기·문법 해부
쉬운 설명 다음에 문법과 실행 순서를 정밀하게 읽습니다.
한 줄로 읽기GitHub Actions의 공식 run URL·commit·실패 report artifact를 사람 검토에 묶고 로컬 Green을 금지하는 외부 실행 계약이다. 다만 실제 GitHub run이 아니다
문법 해부
- `key: value` 줄은 외부 증거의 필수 field와 상태를 고정한다.
- `NOT_RUN_EXTERNAL`은 실패가 아니라 실제 외부 실행을 아직 주장하지 않는 정확한 상태다.
실행 순서
- clean workflow를 작성한다.
- push/PR로 공식 run을 만든다.
- commit과 test summary·artifact를 묶는다.
- 사람이 required check와 실패 artifact를 대조한다.
W22 조각별 정밀 해설
F01-C01 · 원문 1–10줄
- 문법 해부
- 1~10줄의 `원문 1–10줄`을 입력·guard·관찰·cleanup 단계로 나눈다.
- 실제 값 추적
- 항목 전체 흐름에 연결해 `FUTURE_TRIGGER`을 대조한다. 이 값이 chunk 단독 산출이라는 뜻은 아니다.
- 정상 예
- 정상 예에서는 source 순서와 owner 계약이 일치해 `FUTURE_TRIGGER`을 관찰한다.
- 틀린 예·반례
- 반례에서는 선행 guard·stable order·cleanup을 생략한다. 동결 경계: 실제 GitHub run이 아니다.
- 착각 방지
- `원문 1–10줄`이 항목 전체 Green을 단독 증명한다고 읽지 않는다.
- 하지 않는 일
- 이 chunk가 책임지지 않는 범위: 실제 GitHub run이 아니다.
- 다음 연결
- 다음 source chunk의 입력 또는 최종 marker/SQL oracle로 결과를 넘긴다.
F01-C02 · 원문 11–11줄
- 문법 해부
- 11~11줄의 `원문 11–11줄`을 입력·guard·관찰·cleanup 단계로 나눈다.
- 실제 값 추적
- 항목 전체 흐름에 연결해 `NOT_RUN_EXTERNAL`을 대조한다. 이 값이 chunk 단독 산출이라는 뜻은 아니다.
- 정상 예
- 정상 예에서는 source 순서와 owner 계약이 일치해 `NOT_RUN_EXTERNAL`을 관찰한다.
- 틀린 예·반례
- 반례에서는 선행 guard·stable order·cleanup을 생략한다. 동결 경계: 로컬 파일·문자열 검사는 외부 성공을 증명하지 않는다.
- 착각 방지
- `원문 11–11줄`이 항목 전체 Green을 단독 증명한다고 읽지 않는다.
- 하지 않는 일
- 이 chunk가 책임지지 않는 범위: 로컬 파일·문자열 검사는 외부 성공을 증명하지 않는다.
- 다음 연결
- 다음 source chunk의 입력 또는 최종 marker/SQL oracle로 결과를 넘긴다.
반례
-
겉보기에는 맞지만 깨지는 예는?
-
로컬 test 0을 외부 CI Green으로 부른다
-
그 상태는 owner·입력·관찰 중 한 칸이 비어 있어.
-
수정한 뒤 같은 source와 hash로 다시 대조해.
STEP 08 / 13
실제 값 따라가기
같은 입력값이 어느 줄을 지나 어떤 결과가 되는지 추적합니다.
| 순서 | 들어온 값 | 코드가 하는 일 | 나온 값·상태 | 경계 |
|---|---|---|---|---|
| F01-T01 미실행 | local template | state 선언 | NOT_RUN_EXTERNAL | local Green 없음 |
| F01-T02 정상 run | official URL+commit | 사람 대조 | MANUAL_REVIEW_REQUIRED 해소 가능 | required check 별도 |
| F01-T03 고의 실패 | failing commit | always upload | report artifact 유지 | failure가 success로 바뀌는 것은 아님 |
책임 경계
-
이 항목의 마지막 책임선은?
-
직접 역할은 `외부 GitHub Actions evidence 계약`이야.
-
대표 경계는 `장기 credential 부재도 실제 workflow를 검사해야 한다`이야.
-
정본/비정본 label과 evidence owner까지 확인하면 끝이야.
STEP 09 / 13
GitHub·AWS·PowerShell·PostgreSQL 내부에서 벌어지는 일
GitHub·AWS·PowerShell·PostgreSQL에서 실제로 일어나는 일과 증명 범위를 구분합니다.
checkout commit만으로 clean test를 실행한다.
로컬 cache를 증거로 쓰지 않는다.실패 뒤에도 report를 보존한다.
artifact 존재만으로 test 성공은 아니다.required check가 merge 경계를 만든다.
workflow 파일만으로 정책 적용을 증명하지 못한다.STEP 10 / 13
흔한 착각과 틀린 예
그럴듯하지만 틀린 해석을 반례로 고칩니다.
❌ 로컬 test 0을 외부 CI Green으로 부른다
왜 틀리나 외부 GitHub Actions evidence 계약의 owner·관찰·경계 중 적어도 하나를 건너뛴다.
바르게 읽기 clean workflow를 작성한다. 그리고 source의 실제 값과 hash를 다시 대조한다.
반례 반례에서는 `실제 GitHub run이 아니다` 상태인데도 Green을 주장하게 된다.
❌ 성공 캡처만 남기고 URL·commit을 빼먹는다
왜 틀리나 외부 GitHub Actions evidence 계약의 owner·관찰·경계 중 적어도 하나를 건너뛴다.
바르게 읽기 push/PR로 공식 run을 만든다. 그리고 source의 실제 값과 hash를 다시 대조한다.
반례 반례에서는 `로컬 파일·문자열 검사는 외부 성공을 증명하지 않는다` 상태인데도 Green을 주장하게 된다.
❌ 실패 때 report upload를 건너뛴다
왜 틀리나 외부 GitHub Actions evidence 계약의 owner·관찰·경계 중 적어도 하나를 건너뛴다.
바르게 읽기 commit과 test summary·artifact를 묶는다. 그리고 source의 실제 값과 hash를 다시 대조한다.
반례 반례에서는 `required check 설정은 사람이 확인한다` 상태인데도 Green을 주장하게 된다.
❌ 장기 AWS key를 test job에 둔다
왜 틀리나 외부 GitHub Actions evidence 계약의 owner·관찰·경계 중 적어도 하나를 건너뛴다.
바르게 읽기 사람이 required check와 실패 artifact를 대조한다. 그리고 source의 실제 값과 hash를 다시 대조한다.
반례 반례에서는 `장기 credential 부재도 실제 workflow를 검사해야 한다` 상태인데도 Green을 주장하게 된다.
❌ self-declared PASS를 공식 conclusion으로 착각한다
왜 틀리나 외부 GitHub Actions evidence 계약의 owner·관찰·경계 중 적어도 하나를 건너뛴다.
바르게 읽기 사람이 required check와 실패 artifact를 대조한다. 그리고 source의 실제 값과 hash를 다시 대조한다.
반례 반례에서는 `실제 GitHub run이 아니다` 상태인데도 Green을 주장하게 된다.
STEP 11 / 13
이 코드가 보장하지 않는 것
이 코드가 책임지지 않는 일을 분리합니다.
실제 GitHub run이 아니다
이 책임을 맡는 곳: 별도 외부/selector 실행로컬 파일·문자열 검사는 외부 성공을 증명하지 않는다
이 책임을 맡는 곳: secret·운영 정책required check 설정은 사람이 확인한다
이 책임을 맡는 곳: infrastructure·사람 검토장기 credential 부재도 실제 workflow를 검사해야 한다
이 책임을 맡는 곳: owner lifecycleSTEP 12 / 13
직접 다시 써보기
뜻 → 조각 → 전체 코드 순서로 다시 씁니다.
1단계 · 뜻부터 복원
다음 역할을 고정값과 미보장 경계까지 말한다: GitHub Actions의 공식 run URL·commit·실패 report artifact를 사람 검토에 묶고 로컬 Green을 금지하는 외부 실행 계약이다.
2단계 · 코드 조각 재조립
- 원문 1–10줄
- 원문 11–11줄
3단계 · 파일 전체 다시 쓰기
11개 물리 줄을 원본 순서로 복원하고 SHA-256 1cb8a4605cae9d6e9c531b6b33e4f3d3066f27370e3b04043aa7f3b09c10a9dc와 대조한다.
자가 점검
- 원본 source/template bytes를 바꾸지 않았는가?
- 외부 미실행과 local restore Green을 구분했는가?
- secret 원문을 evidence에 남기지 않았는가?
- D7 checked_at 충돌과 사람 검토 경계를 보았는가?
- Q35/Q36을 workbook 정본 답안이라고 부르지 않았는가?
STEP 13 / 13
전체 원본 source
감사로 고정한 전체 source를 가감 없이 확인합니다.
학습용 예시 전체 확인하기 · 정본 답안 아님
학습용 예시 · PDF 외부 실행 계약 · 정본 답안 아님
status: FUTURE_TRIGGER
execution: NOT_RUN_EXTERNAL
required_fields: official_run_url, run_id, commit_sha, workflow_name, conclusion, screenshot_path, screenshot_sha256, artifact_url
url_rule: official HTTPS GitHub Actions run URL
hash_rule: screenshot_sha256 is exact 64-hex hash of screenshot_path
local_green_owner: none
local_restore_owner: scripts/run-w22-restore.ps1 (Saturday)
manual_rule: 승인된 repository의 실제 push/PR 뒤 공식 run URL과 commit SHA를 사람이 대조한다.
failure_artifact_rule: 고의 실패 run에서도 test report artifact가 남아야 한다.
boundary: 로컬 파일 존재·문자열 검사·self-declared PASS는 외부 CI Green이 아니다.
02AWS 경계 — public 443, private app·RDS, 관리 접속은 SSM
illustrative/text/W22-D2-architecture-rules.txt
학습용 예시 · PDF contract/template · 정본 답안 아님 · 학습용 예시 · 정본 답안 아님 · W22-F0211줄 연결11줄 번역2 chunks
AWS 경계 — public 443, private app·RDS, 관리 접속은 SSM
illustrative/text/W22-D2-architecture-rules.txt
학습용 예시 · PDF contract/template · 정본 답안 아님 · 학습용 예시 · 정본 답안 아님 · W22-F02STEP 01 / 13
오늘 이 코드에서 해결할 문제
무엇을 이해해야 하는지 질문부터 잡습니다.
public ALB 443에서 private app 8080과 private RDS 5432로 이어지는 SG-to-SG 최소 AWS 경계를 고정한다.
- `ALB:443 public`은 어느 줄에서 생길까?
- 입력→guard→관찰→cleanup 순서는 무엇인가?
- local owner와 external human review는 누구인가?
- 직접 관찰하지 않은 Green은 무엇인가?
- 반례는 `diagram template은 실제 resource 생성 증거가 아니다`이라는 경계와 어떻게 연결되는가?
ALB:443 publicApp:8080 privateRDS:5432 privateSSM no SSH 22CloudWatchSTEP 02 / 13
아주 짧게: 이 코드는 왜 필요할까?
웹소설 대신 이 코드가 필요한 이유만 두 문단으로 쉽게 봅니다.
STARRY가 GitHub run표·AWS 출입증·DB 복구 영수증·SQL 결과표를 서로 다른 칸에 놓는다.
AWS 경계 — public 443, private app·RDS, 관리 접속은 SSM ― 증거 흐름으로 바꾸기
public ALB 443에서 private app 8080과 private RDS 5432로 이어지는 SG-to-SG 최소 AWS 경계를 고정한다.
핵심값 ALB:443 public, App:8080 private, RDS:5432 private, SSM no SSH 22, CloudWatch을 원본 줄로 따라가되, `diagram template은 실제 resource 생성 증거가 아니다`까지 함께 표시해 Green 범위를 부풀리지 않는다.
딱 여기까지만 비유는 owner와 순서를 기억하게 할 뿐 외부 실행·AWS 계정 상태·PostgreSQL restore·SQL 결과를 자동 증명하지 않는다.
STEP 03 / 13
초등학생도 이해하는 설명
생활 비유와 실제 코드의 경계를 함께 확인합니다.
원문 1–10줄
1~10줄을 한 덩어리로 읽어 1번째 움직임을 본다. public ALB 443에서 private app 8080과 private RDS 5432로 이어지는 SG-to-SG 최소 AWS 경계를 고정한다.
- 코드 연결
1~10줄- 비유
- 거리의 정문은 443 하나만 열고, 주방 8080과 금고 5432는 앞방의 출입증으로만 이어지는 건물 도면
- 비유의 끝
- diagram template은 실제 resource 생성 증거가 아니다
원문 11–11줄
11~11줄을 한 덩어리로 읽어 2번째 움직임을 본다. public ALB 443에서 private app 8080과 private RDS 5432로 이어지는 SG-to-SG 최소 AWS 경계를 고정한다.
- 코드 연결
11~11줄- 비유
- 거리의 정문은 443 하나만 열고, 주방 8080과 금고 5432는 앞방의 출입증으로만 이어지는 건물 도면
- 비유의 끝
- single-instance 학습 설계는 production HA가 아니다
문제의 첫 장면
-
첫 고정값은 `ALB:443 public` 맞아?
-
public ALB 443에서 private app 8080과 private RDS 5432로 이어지는 SG-to-SG 최소 AWS 경계를 고정한다.
-
원문에서 `ALB:443 public`이 생기는 위치를 찾자.
-
그리고 `diagram template은 실제 resource 생성 증거가 아니다`도 같이 적어.
입력에서 결과까지
-
`App:8080 private`은 언제 생겨?
-
ALB 443만 public으로 둔다. → App 8080은 ALB SG에서만 허용한다.
-
RDS 5432는 App SG에서만 허용한다. → 관리 접속은 inbound SSH 없이 SSM으로 한다.
-
관찰값과 `single-instance 학습 설계는 production HA가 아니다`을 분리하면 돼.
STEP 04 / 13
비유 ↔ 코드 전체 연결표
감사 규칙상 연결 대상인 원본 11줄을 빠짐없이 연결합니다.
| 줄 | 정확한 원본 줄 | STARRY 비유 | 실제 뜻·입력·결과·한계 |
|---|---|---|---|
| 1줄F02-L01 | 학습용 예시 · PDF architecture template · 정본 답안 아님 · 그대로 실행 금지 |
거리의 정문은 443 하나만 열고, 주방 8080과 금고 5432는 앞방의 출입증으로만 이어지는 건물 도면 | AWS network·administration 경계 template의 1번째 원문을 앞 guard와 뒤 관찰값 사이에 연결한다.
|
| 2줄F02-L02 | Internet -> ALB: |
거리의 정문은 443 하나만 열고, 주방 8080과 금고 5432는 앞방의 출입증으로만 이어지는 건물 도면 | 인터넷 entry와 private application 사이의 ALB 443 경계를 표현한다.
|
| 3줄F02-L03 | ALB SG -> App: |
거리의 정문은 443 하나만 열고, 주방 8080과 금고 5432는 앞방의 출입증으로만 이어지는 건물 도면 | 인터넷 entry와 private application 사이의 ALB 443 경계를 표현한다.
|
| 4줄F02-L04 | App SG -> RDS PostgreSQL: |
거리의 정문은 443 하나만 열고, 주방 8080과 금고 5432는 앞방의 출입증으로만 이어지는 건물 도면 | private PostgreSQL 5432와 application SG 사이의 DB 경계를 표현한다.
|
| 5줄F02-L05 | Admin -> SSM Session Manager ( |
거리의 정문은 443 하나만 열고, 주방 8080과 금고 5432는 앞방의 출입증으로만 이어지는 건물 도면 | inbound SSH 없이 관리 session 또는 secret metadata를 다루는 AWS 경계를 나타낸다.
|
| 6줄F02-L06 | Secrets -> SSM Parameter Store or Secrets Manager |
거리의 정문은 443 하나만 열고, 주방 8080과 금고 5432는 앞방의 출입증으로만 이어지는 건물 도면 | inbound SSH 없이 관리 session 또는 secret metadata를 다루는 AWS 경계를 나타낸다.
|
| 7줄F02-L07 | Logs/ |
거리의 정문은 443 하나만 열고, 주방 8080과 금고 5432는 앞방의 출입증으로만 이어지는 건물 도면 | AWS network·administration 경계 template의 7번째 원문을 앞 guard와 뒤 관찰값 사이에 연결한다.
|
| 8줄F02-L08 | security_group_rule: |
거리의 정문은 443 하나만 열고, 주방 8080과 금고 5432는 앞방의 출입증으로만 이어지는 건물 도면 | 인터넷 entry와 private application 사이의 ALB 443 경계를 표현한다.
|
| 9줄F02-L09 | database_rule: |
거리의 정문은 443 하나만 열고, 주방 8080과 금고 5432는 앞방의 출입증으로만 이어지는 건물 도면 | private PostgreSQL 5432와 application SG 사이의 DB 경계를 표현한다.
|
| 10줄F02-L10 | cost_boundary: |
거리의 정문은 443 하나만 열고, 주방 8080과 금고 5432는 앞방의 출입증으로만 이어지는 건물 도면 | AWS network·administration 경계 template에서 `cost_boundary: account resource creation require` field·값 또는 assignment를 다음 단계에 전달한다.
|
| 11줄F02-L11 | non_goal: |
거리의 정문은 443 하나만 열고, 주방 8080과 금고 5432는 앞방의 출입증으로만 이어지는 건물 도면 | AWS network·administration 경계 template에서 `non_goal: single-instance learning deployment is` field·값 또는 assignment를 다음 단계에 전달한다.
|
Green 범위
-
marker나 파일이 보이면 전부 성공이야?
-
아니. source가 직접 검증한 범위만 말해야 해.
-
직접 연결되는 대표 값은 `CloudWatch`이야.
-
`RDS public accessibility false는 별도 확인이 필요하다`는 별도 증거가 필요해.
STEP 05 / 13
원본 코드 조각
원본을 2개 의미 조각으로 나누어 그대로 확인합니다.
파일을 한꺼번에 외우지 않고 실행 의미가 이어지는 작은 조각으로 봅니다. 아래 코드는 prompt·fixture·가정을 밝힌 학습용 예시 source이며, 제공 정본 답안이 아닙니다.
학습용 예시 · PDF architecture template · 정본 답안 아님 · 그대로 실행 금지
Internet -> ALB:443 (public)
ALB SG -> App:8080 (private)
App SG -> RDS PostgreSQL:5432 (private)
Admin -> SSM Session Manager (no inbound SSH 22)
Secrets -> SSM Parameter Store or Secrets Manager
Logs/Metrics -> CloudWatch
security_group_rule: App inbound source is ALB SG, not 0.0.0.0/0.
database_rule: RDS public accessibility is false and inbound source is App SG only.
cost_boundary: account resource creation requires a budget and teardown plan first.
non_goal: single-instance learning deployment is not production HA, WAF, or full DR.
STEP 06 / 13
코드 한 줄씩 한국어로 번역
비어 있지 않은 11줄을 모두 한국어로 옮깁니다.
비어 있지 않은 원본 줄은 하나도 생략하지 않습니다.
| 줄 | 원본 | 한국어 번역 |
|---|---|---|
| 1 | 학습용 예시 · PDF architecture template · 정본 답안 아님 · 그대로 실행 금지 | AWS network·administration 경계 template의 1번째 원문을 앞 guard와 뒤 관찰값 사이에 연결한다. |
| 2 | Internet -> ALB:443 (public) | 인터넷 entry와 private application 사이의 ALB 443 경계를 표현한다. |
| 3 | ALB SG -> App:8080 (private) | 인터넷 entry와 private application 사이의 ALB 443 경계를 표현한다. |
| 4 | App SG -> RDS PostgreSQL:5432 (private) | private PostgreSQL 5432와 application SG 사이의 DB 경계를 표현한다. |
| 5 | Admin -> SSM Session Manager (no inbound SSH 22) | inbound SSH 없이 관리 session 또는 secret metadata를 다루는 AWS 경계를 나타낸다. |
| 6 | Secrets -> SSM Parameter Store or Secrets Manager | inbound SSH 없이 관리 session 또는 secret metadata를 다루는 AWS 경계를 나타낸다. |
| 7 | Logs/Metrics -> CloudWatch | AWS network·administration 경계 template의 7번째 원문을 앞 guard와 뒤 관찰값 사이에 연결한다. |
| 8 | security_group_rule: App inbound source is ALB SG, not 0.0.0.0/0. | 인터넷 entry와 private application 사이의 ALB 443 경계를 표현한다. |
| 9 | database_rule: RDS public accessibility is false and inbound source is App SG only. | private PostgreSQL 5432와 application SG 사이의 DB 경계를 표현한다. |
| 10 | cost_boundary: account resource creation requires a budget and teardown plan first. | AWS network·administration 경계 template에서 `cost_boundary: account resource creation require` field·값 또는 assignment를 다음 단계에 전달한다. |
| 11 | non_goal: single-instance learning deployment is not production HA, WAF, or full DR. | AWS network·administration 경계 template에서 `non_goal: single-instance learning deployment is` field·값 또는 assignment를 다음 단계에 전달한다. |
STEP 07 / 13
기존 수준의 한 줄 읽기·문법 해부
쉬운 설명 다음에 문법과 실행 순서를 정밀하게 읽습니다.
한 줄로 읽기public ALB 443에서 private app 8080과 private RDS 5432로 이어지는 SG-to-SG 최소 AWS 경계를 고정한다. 다만 diagram template은 실제 resource 생성 증거가 아니다
문법 해부
- 화살표 왼쪽은 허용 source, 오른쪽은 target port와 public/private 위치다.
- SG-to-SG는 고정 IP 대신 앞 단계 security group identity를 source로 쓴다.
실행 순서
- ALB 443만 public으로 둔다.
- App 8080은 ALB SG에서만 허용한다.
- RDS 5432는 App SG에서만 허용한다.
- 관리 접속은 inbound SSH 없이 SSM으로 한다.
W22 조각별 정밀 해설
F02-C01 · 원문 1–10줄
- 문법 해부
- 1~10줄의 `원문 1–10줄`을 입력·guard·관찰·cleanup 단계로 나눈다.
- 실제 값 추적
- 항목 전체 흐름에 연결해 `ALB:443 public`을 대조한다. 이 값이 chunk 단독 산출이라는 뜻은 아니다.
- 정상 예
- 정상 예에서는 source 순서와 owner 계약이 일치해 `ALB:443 public`을 관찰한다.
- 틀린 예·반례
- 반례에서는 선행 guard·stable order·cleanup을 생략한다. 동결 경계: diagram template은 실제 resource 생성 증거가 아니다.
- 착각 방지
- `원문 1–10줄`이 항목 전체 Green을 단독 증명한다고 읽지 않는다.
- 하지 않는 일
- 이 chunk가 책임지지 않는 범위: diagram template은 실제 resource 생성 증거가 아니다.
- 다음 연결
- 다음 source chunk의 입력 또는 최종 marker/SQL oracle로 결과를 넘긴다.
F02-C02 · 원문 11–11줄
- 문법 해부
- 11~11줄의 `원문 11–11줄`을 입력·guard·관찰·cleanup 단계로 나눈다.
- 실제 값 추적
- 항목 전체 흐름에 연결해 `App:8080 private`을 대조한다. 이 값이 chunk 단독 산출이라는 뜻은 아니다.
- 정상 예
- 정상 예에서는 source 순서와 owner 계약이 일치해 `App:8080 private`을 관찰한다.
- 틀린 예·반례
- 반례에서는 선행 guard·stable order·cleanup을 생략한다. 동결 경계: single-instance 학습 설계는 production HA가 아니다.
- 착각 방지
- `원문 11–11줄`이 항목 전체 Green을 단독 증명한다고 읽지 않는다.
- 하지 않는 일
- 이 chunk가 책임지지 않는 범위: single-instance 학습 설계는 production HA가 아니다.
- 다음 연결
- 다음 source chunk의 입력 또는 최종 marker/SQL oracle로 결과를 넘긴다.
반례
-
겉보기에는 맞지만 깨지는 예는?
-
EC2 8080을 0.0.0.0/0에 연다
-
그 상태는 owner·입력·관찰 중 한 칸이 비어 있어.
-
수정한 뒤 같은 source와 hash로 다시 대조해.
STEP 08 / 13
실제 값 따라가기
같은 입력값이 어느 줄을 지나 어떤 결과가 되는지 추적합니다.
| 순서 | 들어온 값 | 코드가 하는 일 | 나온 값·상태 | 경계 |
|---|---|---|---|---|
| F02-T01 사용자 | Internet | TLS 443 | public ALB | app 8080 직접 공개 금지 |
| F02-T02 application | ALB SG | private 8080 | app target | 0.0.0.0/0 금지 |
| F02-T03 database | App SG | private 5432 | RDS | public accessibility false |
책임 경계
-
이 항목의 마지막 책임선은?
-
직접 역할은 `AWS network·administration 경계 template`이야.
-
대표 경계는 `cost gate 전에 cloud resource를 만들지 않는다`이야.
-
정본/비정본 label과 evidence owner까지 확인하면 끝이야.
STEP 09 / 13
GitHub·AWS·PowerShell·PostgreSQL 내부에서 벌어지는 일
GitHub·AWS·PowerShell·PostgreSQL에서 실제로 일어나는 일과 증명 범위를 구분합니다.
public entry와 private workload subnet을 분리한다.
diagram은 실제 route table 검사가 아니다.stateful inbound source를 앞 SG로 제한한다.
NACL·egress 전체 설계는 별도다.IAM과 agent/channel로 관리 session을 연다.
아무 IAM principal이나 접근할 수 있다는 뜻은 아니다.STEP 10 / 13
흔한 착각과 틀린 예
그럴듯하지만 틀린 해석을 반례로 고칩니다.
❌ EC2 8080을 0.0.0.0/0에 연다
왜 틀리나 AWS network·administration 경계 template의 owner·관찰·경계 중 적어도 하나를 건너뛴다.
바르게 읽기 ALB 443만 public으로 둔다. 그리고 source의 실제 값과 hash를 다시 대조한다.
반례 반례에서는 `diagram template은 실제 resource 생성 증거가 아니다` 상태인데도 Green을 주장하게 된다.
❌ RDS 5432를 개인 IP에 공개한다
왜 틀리나 AWS network·administration 경계 template의 owner·관찰·경계 중 적어도 하나를 건너뛴다.
바르게 읽기 App 8080은 ALB SG에서만 허용한다. 그리고 source의 실제 값과 hash를 다시 대조한다.
반례 반례에서는 `single-instance 학습 설계는 production HA가 아니다` 상태인데도 Green을 주장하게 된다.
❌ SSH 22를 관리 기본값으로 둔다
왜 틀리나 AWS network·administration 경계 template의 owner·관찰·경계 중 적어도 하나를 건너뛴다.
바르게 읽기 RDS 5432는 App SG에서만 허용한다. 그리고 source의 실제 값과 hash를 다시 대조한다.
반례 반례에서는 `RDS public accessibility false는 별도 확인이 필요하다` 상태인데도 Green을 주장하게 된다.
❌ 학습 single instance를 production HA라 부른다
왜 틀리나 AWS network·administration 경계 template의 owner·관찰·경계 중 적어도 하나를 건너뛴다.
바르게 읽기 관리 접속은 inbound SSH 없이 SSM으로 한다. 그리고 source의 실제 값과 hash를 다시 대조한다.
반례 반례에서는 `cost gate 전에 cloud resource를 만들지 않는다` 상태인데도 Green을 주장하게 된다.
❌ budget 없이 NAT·ALB·RDS를 만든다
왜 틀리나 AWS network·administration 경계 template의 owner·관찰·경계 중 적어도 하나를 건너뛴다.
바르게 읽기 관리 접속은 inbound SSH 없이 SSM으로 한다. 그리고 source의 실제 값과 hash를 다시 대조한다.
반례 반례에서는 `diagram template은 실제 resource 생성 증거가 아니다` 상태인데도 Green을 주장하게 된다.
STEP 11 / 13
이 코드가 보장하지 않는 것
이 코드가 책임지지 않는 일을 분리합니다.
diagram template은 실제 resource 생성 증거가 아니다
이 책임을 맡는 곳: 별도 외부/selector 실행single-instance 학습 설계는 production HA가 아니다
이 책임을 맡는 곳: secret·운영 정책RDS public accessibility false는 별도 확인이 필요하다
이 책임을 맡는 곳: infrastructure·사람 검토cost gate 전에 cloud resource를 만들지 않는다
이 책임을 맡는 곳: owner lifecycleSTEP 12 / 13
직접 다시 써보기
뜻 → 조각 → 전체 코드 순서로 다시 씁니다.
1단계 · 뜻부터 복원
다음 역할을 고정값과 미보장 경계까지 말한다: public ALB 443에서 private app 8080과 private RDS 5432로 이어지는 SG-to-SG 최소 AWS 경계를 고정한다.
2단계 · 코드 조각 재조립
- 원문 1–10줄
- 원문 11–11줄
3단계 · 파일 전체 다시 쓰기
11개 물리 줄을 원본 순서로 복원하고 SHA-256 5c765a310a616e11f12ed8ed8ceefc4a1602b89f522021389635ea774f5a6287와 대조한다.
자가 점검
- 원본 source/template bytes를 바꾸지 않았는가?
- 외부 미실행과 local restore Green을 구분했는가?
- secret 원문을 evidence에 남기지 않았는가?
- D7 checked_at 충돌과 사람 검토 경계를 보았는가?
- Q35/Q36을 workbook 정본 답안이라고 부르지 않았는가?
STEP 13 / 13
전체 원본 source
감사로 고정한 전체 source를 가감 없이 확인합니다.
학습용 예시 전체 확인하기 · 정본 답안 아님
학습용 예시 · PDF architecture template · 정본 답안 아님 · 그대로 실행 금지
Internet -> ALB:443 (public)
ALB SG -> App:8080 (private)
App SG -> RDS PostgreSQL:5432 (private)
Admin -> SSM Session Manager (no inbound SSH 22)
Secrets -> SSM Parameter Store or Secrets Manager
Logs/Metrics -> CloudWatch
security_group_rule: App inbound source is ALB SG, not 0.0.0.0/0.
database_rule: RDS public accessibility is false and inbound source is App SG only.
cost_boundary: account resource creation requires a budget and teardown plan first.
non_goal: single-instance learning deployment is not production HA, WAF, or full DR.
03GitHub OIDC — 장기 key 대신 repo-bound 임시 AWS session
illustrative/yaml/W22-D3-oidc-workflow.yml
학습용 예시 · PDF YAML template · 정본 답안 아님 · 그대로 실행 금지 · 학습용 예시 · 정본 답안 아님 · W22-F0313줄 연결13줄 번역2 chunks
GitHub OIDC — 장기 key 대신 repo-bound 임시 AWS session
illustrative/yaml/W22-D3-oidc-workflow.yml
학습용 예시 · PDF YAML template · 정본 답안 아님 · 그대로 실행 금지 · 학습용 예시 · 정본 답안 아님 · W22-F03STEP 01 / 13
오늘 이 코드에서 해결할 문제
무엇을 이해해야 하는지 질문부터 잡습니다.
GitHub OIDC token으로 짧은 AWS session을 받아 장기 access key 없이 deploy role identity부터 확인하는 workflow 골격이다.
- `id-token: write`은 어느 줄에서 생길까?
- 입력→guard→관찰→cleanup 순서는 무엇인가?
- local owner와 external human review는 누구인가?
- 직접 관찰하지 않은 Green은 무엇인가?
- 반례는 `sample account ID는 실제 값이 아니다`이라는 경계와 어떻게 연결되는가?
id-token: writecontents: readconfigure-aws-credentials@v4ap-northeast-2sts get-caller-identitySTEP 02 / 13
아주 짧게: 이 코드는 왜 필요할까?
웹소설 대신 이 코드가 필요한 이유만 두 문단으로 쉽게 봅니다.
STARRY가 GitHub run표·AWS 출입증·DB 복구 영수증·SQL 결과표를 서로 다른 칸에 놓는다.
GitHub OIDC — 장기 key 대신 repo-bound 임시 AWS session ― 증거 흐름으로 바꾸기
GitHub OIDC token으로 짧은 AWS session을 받아 장기 access key 없이 deploy role identity부터 확인하는 workflow 골격이다.
핵심값 id-token: write, contents: read, configure-aws-credentials@v4, ap-northeast-2, sts get-caller-identity을 원본 줄로 따라가되, `sample account ID는 실제 값이 아니다`까지 함께 표시해 Green 범위를 부풀리지 않는다.
딱 여기까지만 비유는 owner와 순서를 기억하게 할 뿐 외부 실행·AWS 계정 상태·PostgreSQL restore·SQL 결과를 자동 증명하지 않는다.
STEP 03 / 13
초등학생도 이해하는 설명
생활 비유와 실제 코드의 경계를 함께 확인합니다.
원문 1–10줄
1~10줄을 한 덩어리로 읽어 1번째 움직임을 본다. GitHub OIDC token으로 짧은 AWS session을 받아 장기 access key 없이 deploy role identity부터 확인하는 workflow 골격이다.
- 코드 연결
1~10줄- 비유
- 창고 열쇠를 GitHub에 오래 보관하지 않고, 정확한 repo 행사표를 보여줄 때만 AWS가 짧은 방문증을 발급하는 방식
- 비유의 끝
- sample account ID는 실제 값이 아니다
원문 11–13줄
11~13줄을 한 덩어리로 읽어 2번째 움직임을 본다. GitHub OIDC token으로 짧은 AWS session을 받아 장기 access key 없이 deploy role identity부터 확인하는 workflow 골격이다.
- 코드 연결
11~13줄- 비유
- 창고 열쇠를 GitHub에 오래 보관하지 않고, 정확한 repo 행사표를 보여줄 때만 AWS가 짧은 방문증을 발급하는 방식
- 비유의 끝
- trust sub를 repo와 branch/environment에 제한해야 한다
문제의 첫 장면
-
첫 고정값은 `id-token: write` 맞아?
-
GitHub OIDC token으로 짧은 AWS session을 받아 장기 access key 없이 deploy role identity부터 확인하는 workflow 골격이다.
-
원문에서 `id-token: write`이 생기는 위치를 찾자.
-
그리고 `sample account ID는 실제 값이 아니다`도 같이 적어.
입력에서 결과까지
-
`contents: read`은 언제 생겨?
-
OIDC provider와 trust를 만든다. → repo·branch/environment sub를 제한한다.
-
workflow가 role을 assume한다. → 첫 API로 STS caller identity를 확인한다.
-
관찰값과 `trust sub를 repo와 branch/environment에 제한해야 한다`을 분리하면 돼.
STEP 04 / 13
비유 ↔ 코드 전체 연결표
감사 규칙상 연결 대상인 원본 13줄을 빠짐없이 연결합니다.
| 줄 | 정확한 원본 줄 | STARRY 비유 | 실제 뜻·입력·결과·한계 |
|---|---|---|---|
| 1줄F03-L01 | # 학습용 예시 · PDF OIDC template · 정본 답안 아님 · 그대로 실행 금지 |
창고 열쇠를 GitHub에 오래 보관하지 않고, 정확한 repo 행사표를 보여줄 때만 AWS가 짧은 방문증을 발급하는 방식 | 이 source의 비정본 provenance, 가정, 반례, 또는 실행 경계를 사람이 확인할 주석이다.
|
| 2줄F03-L02 | permissions: |
창고 열쇠를 GitHub에 오래 보관하지 않고, 정확한 repo 행사표를 보여줄 때만 AWS가 짧은 방문증을 발급하는 방식 | GitHub OIDC 최소권한 workflow template에서 `permissions:` field·값 또는 assignment를 다음 단계에 전달한다.
|
| 3줄F03-L03 | id-token: |
창고 열쇠를 GitHub에 오래 보관하지 않고, 정확한 repo 행사표를 보여줄 때만 AWS가 짧은 방문증을 발급하는 방식 | GitHub job이 OIDC identity token을 요청할 최소 permission을 선언한다.
|
| 4줄F03-L04 | contents: |
창고 열쇠를 GitHub에 오래 보관하지 않고, 정확한 repo 행사표를 보여줄 때만 AWS가 짧은 방문증을 발급하는 방식 | GitHub OIDC 최소권한 workflow template에서 `contents: read` field·값 또는 assignment를 다음 단계에 전달한다.
|
| 5줄F03-L05 | steps: |
창고 열쇠를 GitHub에 오래 보관하지 않고, 정확한 repo 행사표를 보여줄 때만 AWS가 짧은 방문증을 발급하는 방식 | GitHub OIDC 최소권한 workflow template에서 `steps:` field·값 또는 assignment를 다음 단계에 전달한다.
|
| 6줄F03-L06 | - uses: |
창고 열쇠를 GitHub에 오래 보관하지 않고, 정확한 repo 행사표를 보여줄 때만 AWS가 짧은 방문증을 발급하는 방식 | GitHub OIDC token으로 AWS deploy role의 임시 session을 구성한다.
|
| 7줄F03-L07 | with: |
창고 열쇠를 GitHub에 오래 보관하지 않고, 정확한 repo 행사표를 보여줄 때만 AWS가 짧은 방문증을 발급하는 방식 | GitHub OIDC 최소권한 workflow template에서 `with:` field·값 또는 assignment를 다음 단계에 전달한다.
|
| 8줄F03-L08 | role-to-assume: |
창고 열쇠를 GitHub에 오래 보관하지 않고, 정확한 repo 행사표를 보여줄 때만 AWS가 짧은 방문증을 발급하는 방식 | GitHub OIDC 최소권한 workflow template에서 `role-to-assume: arn:aws:iam::123456789012:role/f` field·값 또는 assignment를 다음 단계에 전달한다.
|
| 9줄F03-L09 | aws-region: |
창고 열쇠를 GitHub에 오래 보관하지 않고, 정확한 repo 행사표를 보여줄 때만 AWS가 짧은 방문증을 발급하는 방식 | GitHub OIDC 최소권한 workflow template에서 `aws-region: ap-northeast-2` field·값 또는 assignment를 다음 단계에 전달한다.
|
| 10줄F03-L10 | - run: |
창고 열쇠를 GitHub에 오래 보관하지 않고, 정확한 repo 행사표를 보여줄 때만 AWS가 짧은 방문증을 발급하는 방식 | 현재 AWS session이 의도한 caller인지 먼저 관찰한다.
|
| 11줄F03-L11 | # 실제 trust policy는 정확한 repository와 main 또는 승인 environment의 sub claim으로 제한한다. |
창고 열쇠를 GitHub에 오래 보관하지 않고, 정확한 repo 행사표를 보여줄 때만 AWS가 짧은 방문증을 발급하는 방식 | 이 source의 비정본 provenance, 가정, 반례, 또는 실행 경계를 사람이 확인할 주석이다.
|
| 12줄F03-L12 | # AWS_ACCESS_KEY_ID·AWS_SECRET_ACCESS_KEY 같은 장기 정적 key를 workflow secret에 저장하지 않는다. |
창고 열쇠를 GitHub에 오래 보관하지 않고, 정확한 repo 행사표를 보여줄 때만 AWS가 짧은 방문증을 발급하는 방식 | 이 source의 비정본 provenance, 가정, 반례, 또는 실행 경계를 사람이 확인할 주석이다.
|
| 13줄F03-L13 | # 이 조각은 외부 assume-role 성공을 증명하지 않으며 공식 run 증거는 MANUAL_REVIEW_REQUIRED다. |
창고 열쇠를 GitHub에 오래 보관하지 않고, 정확한 repo 행사표를 보여줄 때만 AWS가 짧은 방문증을 발급하는 방식 | 자동 shape/hash 검사 뒤에도 사람의 의미 검토가 남았음을 고정한다.
|
Green 범위
-
marker나 파일이 보이면 전부 성공이야?
-
아니. source가 직접 검증한 범위만 말해야 해.
-
직접 연결되는 대표 값은 `sts get-caller-identity`이야.
-
`AdministratorAccess를 허용하지 않는다`는 별도 증거가 필요해.
STEP 05 / 13
원본 코드 조각
원본을 2개 의미 조각으로 나누어 그대로 확인합니다.
파일을 한꺼번에 외우지 않고 실행 의미가 이어지는 작은 조각으로 봅니다. 아래 코드는 prompt·fixture·가정을 밝힌 학습용 예시 source이며, 제공 정본 답안이 아닙니다.
# 학습용 예시 · PDF OIDC template · 정본 답안 아님 · 그대로 실행 금지
permissions:
id-token: write
contents: read
steps:
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::123456789012:role/fcl-github-deploy
aws-region: ap-northeast-2
- run: aws sts get-caller-identity
# 실제 trust policy는 정확한 repository와 main 또는 승인 environment의 sub claim으로 제한한다.
# AWS_ACCESS_KEY_ID·AWS_SECRET_ACCESS_KEY 같은 장기 정적 key를 workflow secret에 저장하지 않는다.
# 이 조각은 외부 assume-role 성공을 증명하지 않으며 공식 run 증거는 MANUAL_REVIEW_REQUIRED다.
STEP 06 / 13
코드 한 줄씩 한국어로 번역
비어 있지 않은 13줄을 모두 한국어로 옮깁니다.
비어 있지 않은 원본 줄은 하나도 생략하지 않습니다.
| 줄 | 원본 | 한국어 번역 |
|---|---|---|
| 1 | # 학습용 예시 · PDF OIDC template · 정본 답안 아님 · 그대로 실행 금지 | 이 source의 비정본 provenance, 가정, 반례, 또는 실행 경계를 사람이 확인할 주석이다. |
| 2 | permissions: | GitHub OIDC 최소권한 workflow template에서 `permissions:` field·값 또는 assignment를 다음 단계에 전달한다. |
| 3 | id-token: write | GitHub job이 OIDC identity token을 요청할 최소 permission을 선언한다. |
| 4 | contents: read | GitHub OIDC 최소권한 workflow template에서 `contents: read` field·값 또는 assignment를 다음 단계에 전달한다. |
| 5 | steps: | GitHub OIDC 최소권한 workflow template에서 `steps:` field·값 또는 assignment를 다음 단계에 전달한다. |
| 6 | - uses: aws-actions/configure-aws-credentials@v4 | GitHub OIDC token으로 AWS deploy role의 임시 session을 구성한다. |
| 7 | with: | GitHub OIDC 최소권한 workflow template에서 `with:` field·값 또는 assignment를 다음 단계에 전달한다. |
| 8 | role-to-assume: arn:aws:iam::123456789012:role/fcl-github-deploy | GitHub OIDC 최소권한 workflow template에서 `role-to-assume: arn:aws:iam::123456789012:role/f` field·값 또는 assignment를 다음 단계에 전달한다. |
| 9 | aws-region: ap-northeast-2 | GitHub OIDC 최소권한 workflow template에서 `aws-region: ap-northeast-2` field·값 또는 assignment를 다음 단계에 전달한다. |
| 10 | - run: aws sts get-caller-identity | 현재 AWS session이 의도한 caller인지 먼저 관찰한다. |
| 11 | # 실제 trust policy는 정확한 repository와 main 또는 승인 environment의 sub claim으로 제한한다. | 이 source의 비정본 provenance, 가정, 반례, 또는 실행 경계를 사람이 확인할 주석이다. |
| 12 | # AWS_ACCESS_KEY_ID·AWS_SECRET_ACCESS_KEY 같은 장기 정적 key를 workflow secret에 저장하지 않는다. | 이 source의 비정본 provenance, 가정, 반례, 또는 실행 경계를 사람이 확인할 주석이다. |
| 13 | # 이 조각은 외부 assume-role 성공을 증명하지 않으며 공식 run 증거는 MANUAL_REVIEW_REQUIRED다. | 자동 shape/hash 검사 뒤에도 사람의 의미 검토가 남았음을 고정한다. |
STEP 07 / 13
기존 수준의 한 줄 읽기·문법 해부
쉬운 설명 다음에 문법과 실행 순서를 정밀하게 읽습니다.
한 줄로 읽기GitHub OIDC token으로 짧은 AWS session을 받아 장기 access key 없이 deploy role identity부터 확인하는 workflow 골격이다. 다만 sample account ID는 실제 값이 아니다
문법 해부
- `permissions.id-token: write`가 GitHub OIDC token 발급을 허용한다.
- `role-to-assume`와 trust `sub` 조건은 workflow 쪽과 AWS 쪽을 함께 묶어야 한다.
실행 순서
- OIDC provider와 trust를 만든다.
- repo·branch/environment sub를 제한한다.
- workflow가 role을 assume한다.
- 첫 API로 STS caller identity를 확인한다.
W22 조각별 정밀 해설
F03-C01 · 원문 1–10줄
- 문법 해부
- 1~10줄의 `원문 1–10줄`을 입력·guard·관찰·cleanup 단계로 나눈다.
- 실제 값 추적
- 항목 전체 흐름에 연결해 `id-token: write`을 대조한다. 이 값이 chunk 단독 산출이라는 뜻은 아니다.
- 정상 예
- 정상 예에서는 source 순서와 owner 계약이 일치해 `id-token: write`을 관찰한다.
- 틀린 예·반례
- 반례에서는 선행 guard·stable order·cleanup을 생략한다. 동결 경계: sample account ID는 실제 값이 아니다.
- 착각 방지
- `원문 1–10줄`이 항목 전체 Green을 단독 증명한다고 읽지 않는다.
- 하지 않는 일
- 이 chunk가 책임지지 않는 범위: sample account ID는 실제 값이 아니다.
- 다음 연결
- 다음 source chunk의 입력 또는 최종 marker/SQL oracle로 결과를 넘긴다.
F03-C02 · 원문 11–13줄
- 문법 해부
- 11~13줄의 `원문 11–13줄`을 입력·guard·관찰·cleanup 단계로 나눈다.
- 실제 값 추적
- 항목 전체 흐름에 연결해 `contents: read`을 대조한다. 이 값이 chunk 단독 산출이라는 뜻은 아니다.
- 정상 예
- 정상 예에서는 source 순서와 owner 계약이 일치해 `contents: read`을 관찰한다.
- 틀린 예·반례
- 반례에서는 선행 guard·stable order·cleanup을 생략한다. 동결 경계: trust sub를 repo와 branch/environment에 제한해야 한다.
- 착각 방지
- `원문 11–13줄`이 항목 전체 Green을 단독 증명한다고 읽지 않는다.
- 하지 않는 일
- 이 chunk가 책임지지 않는 범위: trust sub를 repo와 branch/environment에 제한해야 한다.
- 다음 연결
- 다음 source chunk의 입력 또는 최종 marker/SQL oracle로 결과를 넘긴다.
반례
-
겉보기에는 맞지만 깨지는 예는?
-
AWS_ACCESS_KEY_ID를 repository secret에 장기 보관한다
-
그 상태는 owner·입력·관찰 중 한 칸이 비어 있어.
-
수정한 뒤 같은 source와 hash로 다시 대조해.
STEP 08 / 13
실제 값 따라가기
같은 입력값이 어느 줄을 지나 어떤 결과가 되는지 추적합니다.
| 순서 | 들어온 값 | 코드가 하는 일 | 나온 값·상태 | 경계 |
|---|---|---|---|---|
| F03-T01 token | approved workflow | OIDC 발급 | short-lived assertion | AWS key가 아님 |
| F03-T02 assume | token claims | trust policy | temporary session | repo wildcard 금지 |
| F03-T03 probe | session | sts identity | assumed role | deploy 권한 전체 Green 아님 |
책임 경계
-
이 항목의 마지막 책임선은?
-
직접 역할은 `GitHub OIDC 최소권한 workflow template`이야.
-
대표 경계는 `외부 assume-role 성공은 공식 run으로 검토한다`이야.
-
정본/비정본 label과 evidence owner까지 확인하면 끝이야.
STEP 09 / 13
GitHub·AWS·PowerShell·PostgreSQL 내부에서 벌어지는 일
GitHub·AWS·PowerShell·PostgreSQL에서 실제로 일어나는 일과 증명 범위를 구분합니다.
job identity claim을 서명된 token으로 만든다.
id-token write가 contents write를 뜻하지 않는다.trust가 맞을 때 임시 credential을 발급한다.
policy action은 별도 최소화가 필요하다.trust policy와 permission policy가 각각 who와 what을 제한한다.
AdministratorAccess는 최소권한이 아니다.STEP 10 / 13
흔한 착각과 틀린 예
그럴듯하지만 틀린 해석을 반례로 고칩니다.
❌ AWS_ACCESS_KEY_ID를 repository secret에 장기 보관한다
왜 틀리나 GitHub OIDC 최소권한 workflow template의 owner·관찰·경계 중 적어도 하나를 건너뛴다.
바르게 읽기 OIDC provider와 trust를 만든다. 그리고 source의 실제 값과 hash를 다시 대조한다.
반례 반례에서는 `sample account ID는 실제 값이 아니다` 상태인데도 Green을 주장하게 된다.
❌ trust sub에 모든 repository wildcard를 쓴다
왜 틀리나 GitHub OIDC 최소권한 workflow template의 owner·관찰·경계 중 적어도 하나를 건너뛴다.
바르게 읽기 repo·branch/environment sub를 제한한다. 그리고 source의 실제 값과 hash를 다시 대조한다.
반례 반례에서는 `trust sub를 repo와 branch/environment에 제한해야 한다` 상태인데도 Green을 주장하게 된다.
❌ AdministratorAccess로 먼저 통과시킨다
왜 틀리나 GitHub OIDC 최소권한 workflow template의 owner·관찰·경계 중 적어도 하나를 건너뛴다.
바르게 읽기 workflow가 role을 assume한다. 그리고 source의 실제 값과 hash를 다시 대조한다.
반례 반례에서는 `AdministratorAccess를 허용하지 않는다` 상태인데도 Green을 주장하게 된다.
❌ sample account ID를 실제 role ARN처럼 쓴다
왜 틀리나 GitHub OIDC 최소권한 workflow template의 owner·관찰·경계 중 적어도 하나를 건너뛴다.
바르게 읽기 첫 API로 STS caller identity를 확인한다. 그리고 source의 실제 값과 hash를 다시 대조한다.
반례 반례에서는 `외부 assume-role 성공은 공식 run으로 검토한다` 상태인데도 Green을 주장하게 된다.
❌ STS identity 성공을 배포 전체 Green으로 부른다
왜 틀리나 GitHub OIDC 최소권한 workflow template의 owner·관찰·경계 중 적어도 하나를 건너뛴다.
바르게 읽기 첫 API로 STS caller identity를 확인한다. 그리고 source의 실제 값과 hash를 다시 대조한다.
반례 반례에서는 `sample account ID는 실제 값이 아니다` 상태인데도 Green을 주장하게 된다.
STEP 11 / 13
이 코드가 보장하지 않는 것
이 코드가 책임지지 않는 일을 분리합니다.
sample account ID는 실제 값이 아니다
이 책임을 맡는 곳: 별도 외부/selector 실행trust sub를 repo와 branch/environment에 제한해야 한다
이 책임을 맡는 곳: secret·운영 정책AdministratorAccess를 허용하지 않는다
이 책임을 맡는 곳: infrastructure·사람 검토외부 assume-role 성공은 공식 run으로 검토한다
이 책임을 맡는 곳: owner lifecycleSTEP 12 / 13
직접 다시 써보기
뜻 → 조각 → 전체 코드 순서로 다시 씁니다.
1단계 · 뜻부터 복원
다음 역할을 고정값과 미보장 경계까지 말한다: GitHub OIDC token으로 짧은 AWS session을 받아 장기 access key 없이 deploy role identity부터 확인하는 workflow 골격이다.
2단계 · 코드 조각 재조립
- 원문 1–10줄
- 원문 11–13줄
3단계 · 파일 전체 다시 쓰기
13개 물리 줄을 원본 순서로 복원하고 SHA-256 00c9735277fe975fe6304610dc3856d41ed2ccd390793ca286a8526d122a05d6와 대조한다.
자가 점검
- 원본 source/template bytes를 바꾸지 않았는가?
- 외부 미실행과 local restore Green을 구분했는가?
- secret 원문을 evidence에 남기지 않았는가?
- D7 checked_at 충돌과 사람 검토 경계를 보았는가?
- Q35/Q36을 workbook 정본 답안이라고 부르지 않았는가?
STEP 13 / 13
전체 원본 source
감사로 고정한 전체 source를 가감 없이 확인합니다.
학습용 예시 전체 확인하기 · 정본 답안 아님
# 학습용 예시 · PDF OIDC template · 정본 답안 아님 · 그대로 실행 금지
permissions:
id-token: write
contents: read
steps:
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::123456789012:role/fcl-github-deploy
aws-region: ap-northeast-2
- run: aws sts get-caller-identity
# 실제 trust policy는 정확한 repository와 main 또는 승인 environment의 sub claim으로 제한한다.
# AWS_ACCESS_KEY_ID·AWS_SECRET_ACCESS_KEY 같은 장기 정적 key를 workflow secret에 저장하지 않는다.
# 이 조각은 외부 assume-role 성공을 증명하지 않으며 공식 run 증거는 MANUAL_REVIEW_REQUIRED다.
04배포 manifest — commit·immutable digest·실제 migration inventory 연결
illustrative/json/W22-D4-deployment-manifest.json
학습용 예시 · PDF JSON schema/worksheet · 정본 답안 아님 · 비실행 · 학습용 예시 · 정본 답안 아님 · W22-F0421줄 연결21줄 번역3 chunks
배포 manifest — commit·immutable digest·실제 migration inventory 연결
illustrative/json/W22-D4-deployment-manifest.json
학습용 예시 · PDF JSON schema/worksheet · 정본 답안 아님 · 비실행 · 학습용 예시 · 정본 답안 아님 · W22-F04STEP 01 / 13
오늘 이 코드에서 해결할 문제
무엇을 이해해야 하는지 질문부터 잡습니다.
source commit·immutable image digest·실제 Flyway migration inventory hash를 한 manifest에 연결하는 비실행 schema다.
- `40-char git SHA`은 어느 줄에서 생길까?
- 입력→guard→관찰→cleanup 순서는 무엇인가?
- local owner와 external human review는 누구인가?
- 직접 관찰하지 않은 Green은 무엇인가?
- 반례는 `0과 example 값은 실제 배포 증거가 아니다`이라는 경계와 어떻게 연결되는가?
40-char git SHArepository@sha256Java 21V001/V019 expected scriptsMANUAL_REVIEW_REQUIREDSTEP 02 / 13
아주 짧게: 이 코드는 왜 필요할까?
웹소설 대신 이 코드가 필요한 이유만 두 문단으로 쉽게 봅니다.
STARRY가 GitHub run표·AWS 출입증·DB 복구 영수증·SQL 결과표를 서로 다른 칸에 놓는다.
배포 manifest — commit·immutable digest·실제 migration inventory 연결 ― 증거 흐름으로 바꾸기
source commit·immutable image digest·실제 Flyway migration inventory hash를 한 manifest에 연결하는 비실행 schema다.
핵심값 40-char git SHA, repository@sha256, Java 21, V001/V019 expected scripts, MANUAL_REVIEW_REQUIRED을 원본 줄로 따라가되, `0과 example 값은 실제 배포 증거가 아니다`까지 함께 표시해 Green 범위를 부풀리지 않는다.
딱 여기까지만 비유는 owner와 순서를 기억하게 할 뿐 외부 실행·AWS 계정 상태·PostgreSQL restore·SQL 결과를 자동 증명하지 않는다.
STEP 03 / 13
초등학생도 이해하는 설명
생활 비유와 실제 코드의 경계를 함께 확인합니다.
원문 1–10줄
1~10줄을 한 덩어리로 읽어 1번째 움직임을 본다. source commit·immutable image digest·실제 Flyway migration inventory hash를 한 manifest에 연결하는 비실행 schema다.
- 코드 연결
1~10줄- 비유
- 상품의 원재료 commit, 밀봉 번호 digest, 사용한 조리법 migration 목록을 한 영수증에 묶는 배포 추적표
- 비유의 끝
- 0과 example 값은 실제 배포 증거가 아니다
원문 11–20줄
11~20줄을 한 덩어리로 읽어 2번째 움직임을 본다. source commit·immutable image digest·실제 Flyway migration inventory hash를 한 manifest에 연결하는 비실행 schema다.
- 코드 연결
11~20줄- 비유
- 상품의 원재료 commit, 밀봉 번호 digest, 사용한 조리법 migration 목록을 한 영수증에 묶는 배포 추적표
- 비유의 끝
- V001/V019는 packaged reference 예상값일 뿐 실제 history를 읽어야 한다
원문 21–21줄
21~21줄을 한 덩어리로 읽어 3번째 움직임을 본다. source commit·immutable image digest·실제 Flyway migration inventory hash를 한 manifest에 연결하는 비실행 schema다.
- 코드 연결
21~21줄- 비유
- 상품의 원재료 commit, 밀봉 번호 digest, 사용한 조리법 migration 목록을 한 영수증에 묶는 배포 추적표
- 비유의 끝
- generic hash 검사는 값의 의미를 증명하지 않는다
문제의 첫 장면
-
첫 고정값은 `40-char git SHA` 맞아?
-
source commit·immutable image digest·실제 Flyway migration inventory hash를 한 manifest에 연결하는 비실행 schema다.
-
원문에서 `40-char git SHA`이 생기는 위치를 찾자.
-
그리고 `0과 example 값은 실제 배포 증거가 아니다`도 같이 적어.
입력에서 결과까지
-
`repository@sha256`은 언제 생겨?
-
실제 git SHA를 읽는다. → registry immutable digest를 읽는다.
-
DB schema history를 export한다. → inventory file hash와 manual status를 manifest에 쓴다.
-
관찰값과 `V001/V019는 packaged reference 예상값일 뿐 실제 history를 읽어야 한다`을 분리하면 돼.
STEP 04 / 13
비유 ↔ 코드 전체 연결표
감사 규칙상 연결 대상인 원본 21줄을 빠짐없이 연결합니다.
| 줄 | 정확한 원본 줄 | STARRY 비유 | 실제 뜻·입력·결과·한계 |
|---|---|---|---|
| 1줄F04-L01 | { |
상품의 원재료 commit, 밀봉 번호 digest, 사용한 조리법 migration 목록을 한 영수증에 묶는 배포 추적표 | 현재 object·array·block 또는 query 범위를 열거나 닫아 구조를 유지한다.
|
| 2줄F04-L02 | "_provenance": |
상품의 원재료 commit, 밀봉 번호 digest, 사용한 조리법 migration 목록을 한 영수증에 묶는 배포 추적표 | immutable 배포 provenance manifest schema에서 `"_provenance": "학습용 예시 · PDF manifest schema · 정` field·값 또는 assignment를 다음 단계에 전달한다.
|
| 3줄F04-L03 | "gitSha": |
상품의 원재료 commit, 밀봉 번호 digest, 사용한 조리법 migration 목록을 한 영수증에 묶는 배포 추적표 | 배포 source snapshot을 실제 40-hex commit SHA field에 연결한다.
|
| 4줄F04-L04 | "image": |
상품의 원재료 commit, 밀봉 번호 digest, 사용한 조리법 migration 목록을 한 영수증에 묶는 배포 추적표 | 현재 file bytes를 64-hex SHA-256 값과 결박하는 field 또는 검사를 다룬다.
|
| 5줄F04-L05 | "java": |
상품의 원재료 commit, 밀봉 번호 digest, 사용한 조리법 migration 목록을 한 영수증에 묶는 배포 추적표 | immutable 배포 provenance manifest schema에서 `"java": "21",` field·값 또는 assignment를 다음 단계에 전달한다.
|
| 6줄F04-L06 | "springBoot": |
상품의 원재료 commit, 밀봉 번호 digest, 사용한 조리법 migration 목록을 한 영수증에 묶는 배포 추적표 | immutable 배포 provenance manifest schema에서 `"springBoot": "4.1.0",` field·값 또는 assignment를 다음 단계에 전달한다.
|
| 7줄F04-L07 | "dbMigrations": |
상품의 원재료 commit, 밀봉 번호 digest, 사용한 조리법 migration 목록을 한 영수증에 묶는 배포 추적표 | 실제 schema history에서 읽을 migration inventory 배열을 연다.
|
| 8줄F04-L08 | { |
상품의 원재료 commit, 밀봉 번호 digest, 사용한 조리법 migration 목록을 한 영수증에 묶는 배포 추적표 | 현재 object·array·block 또는 query 범위를 열거나 닫아 구조를 유지한다.
|
| 9줄F04-L09 | "version": |
상품의 원재료 commit, 밀봉 번호 digest, 사용한 조리법 migration 목록을 한 영수증에 묶는 배포 추적표 | immutable 배포 provenance manifest schema에서 `"version": "001",` field·값 또는 assignment를 다음 단계에 전달한다.
|
| 10줄F04-L10 | "script": |
상품의 원재료 commit, 밀봉 번호 digest, 사용한 조리법 migration 목록을 한 영수증에 묶는 배포 추적표 | immutable 배포 provenance manifest schema에서 `"script": "V001__common.sql",` field·값 또는 assignment를 다음 단계에 전달한다.
|
| 11줄F04-L11 | "checksum": |
상품의 원재료 commit, 밀봉 번호 digest, 사용한 조리법 migration 목록을 한 영수증에 묶는 배포 추적표 | immutable 배포 provenance manifest schema에서 `"checksum": "EXAMPLE_FLYWAY_CHECKSUM"` field·값 또는 assignment를 다음 단계에 전달한다.
|
| 12줄F04-L12 | }, |
상품의 원재료 commit, 밀봉 번호 digest, 사용한 조리법 migration 목록을 한 영수증에 묶는 배포 추적표 | 현재 object·array·block 또는 query 범위를 열거나 닫아 구조를 유지한다.
|
| 13줄F04-L13 | { |
상품의 원재료 commit, 밀봉 번호 digest, 사용한 조리법 migration 목록을 한 영수증에 묶는 배포 추적표 | 현재 object·array·block 또는 query 범위를 열거나 닫아 구조를 유지한다.
|
| 14줄F04-L14 | "version": |
상품의 원재료 commit, 밀봉 번호 digest, 사용한 조리법 migration 목록을 한 영수증에 묶는 배포 추적표 | immutable 배포 provenance manifest schema에서 `"version": "019",` field·값 또는 assignment를 다음 단계에 전달한다.
|
| 15줄F04-L15 | "script": |
상품의 원재료 commit, 밀봉 번호 digest, 사용한 조리법 migration 목록을 한 영수증에 묶는 배포 추적표 | immutable 배포 provenance manifest schema에서 `"script": "V019__audit.sql",` field·값 또는 assignment를 다음 단계에 전달한다.
|
| 16줄F04-L16 | "checksum": |
상품의 원재료 commit, 밀봉 번호 digest, 사용한 조리법 migration 목록을 한 영수증에 묶는 배포 추적표 | immutable 배포 provenance manifest schema에서 `"checksum": "EXAMPLE_FLYWAY_CHECKSUM"` field·값 또는 assignment를 다음 단계에 전달한다.
|
| 17줄F04-L17 | } |
상품의 원재료 commit, 밀봉 번호 digest, 사용한 조리법 migration 목록을 한 영수증에 묶는 배포 추적표 | 현재 object·array·block 또는 query 범위를 열거나 닫아 구조를 유지한다.
|
| 18줄F04-L18 | ], |
상품의 원재료 commit, 밀봉 번호 digest, 사용한 조리법 migration 목록을 한 영수증에 묶는 배포 추적표 | 현재 object·array·block 또는 query 범위를 열거나 닫아 구조를 유지한다.
|
| 19줄F04-L19 | "dbMigrationInventorySha256": |
상품의 원재료 commit, 밀봉 번호 digest, 사용한 조리법 migration 목록을 한 영수증에 묶는 배포 추적표 | 현재 file bytes를 64-hex SHA-256 값과 결박하는 field 또는 검사를 다룬다.
|
| 20줄F04-L20 | "verificationStatus": |
상품의 원재료 commit, 밀봉 번호 digest, 사용한 조리법 migration 목록을 한 영수증에 묶는 배포 추적표 | 자동 shape/hash 검사 뒤에도 사람의 의미 검토가 남았음을 고정한다.
|
| 21줄F04-L21 | } |
상품의 원재료 commit, 밀봉 번호 digest, 사용한 조리법 migration 목록을 한 영수증에 묶는 배포 추적표 | 현재 object·array·block 또는 query 범위를 열거나 닫아 구조를 유지한다.
|
Green 범위
-
marker나 파일이 보이면 전부 성공이야?
-
아니. source가 직접 검증한 범위만 말해야 해.
-
직접 연결되는 대표 값은 `MANUAL_REVIEW_REQUIRED`이야.
-
`generic hash 검사는 값의 의미를 증명하지 않는다`는 별도 증거가 필요해.
STEP 05 / 13
원본 코드 조각
원본을 3개 의미 조각으로 나누어 그대로 확인합니다.
파일을 한꺼번에 외우지 않고 실행 의미가 이어지는 작은 조각으로 봅니다. 아래 코드는 prompt·fixture·가정을 밝힌 학습용 예시 source이며, 제공 정본 답안이 아닙니다.
{
"_provenance": "학습용 예시 · PDF manifest schema · 정본 답안 아님 · 비실행",
"gitSha": "0000000000000000000000000000000000000000",
"image": "example.invalid/financial-core@sha256:0000000000000000000000000000000000000000000000000000000000000000",
"java": "21",
"springBoot": "4.1.0",
"dbMigrations": [
{
"version": "001",
"script": "V001__common.sql",
"checksum": "EXAMPLE_FLYWAY_CHECKSUM"
},
{
"version": "019",
"script": "V019__audit.sql",
"checksum": "EXAMPLE_FLYWAY_CHECKSUM"
}
],
"dbMigrationInventorySha256": "0000000000000000000000000000000000000000000000000000000000000000",
"verificationStatus": "MANUAL_REVIEW_REQUIRED"
}
STEP 06 / 13
코드 한 줄씩 한국어로 번역
비어 있지 않은 21줄을 모두 한국어로 옮깁니다.
비어 있지 않은 원본 줄은 하나도 생략하지 않습니다.
| 줄 | 원본 | 한국어 번역 |
|---|---|---|
| 1 | { | 현재 object·array·block 또는 query 범위를 열거나 닫아 구조를 유지한다. |
| 2 | "_provenance": "학습용 예시 · PDF manifest schema · 정본 답안 아님 · 비실행", | immutable 배포 provenance manifest schema에서 `"_provenance": "학습용 예시 · PDF manifest schema · 정` field·값 또는 assignment를 다음 단계에 전달한다. |
| 3 | "gitSha": "0000000000000000000000000000000000000000", | 배포 source snapshot을 실제 40-hex commit SHA field에 연결한다. |
| 4 | "image": "example.invalid/financial-core@sha256:0000000000000000000000000000000000000000000000000000000000000000", | 현재 file bytes를 64-hex SHA-256 값과 결박하는 field 또는 검사를 다룬다. |
| 5 | "java": "21", | immutable 배포 provenance manifest schema에서 `"java": "21",` field·값 또는 assignment를 다음 단계에 전달한다. |
| 6 | "springBoot": "4.1.0", | immutable 배포 provenance manifest schema에서 `"springBoot": "4.1.0",` field·값 또는 assignment를 다음 단계에 전달한다. |
| 7 | "dbMigrations": [ | 실제 schema history에서 읽을 migration inventory 배열을 연다. |
| 8 | { | 현재 object·array·block 또는 query 범위를 열거나 닫아 구조를 유지한다. |
| 9 | "version": "001", | immutable 배포 provenance manifest schema에서 `"version": "001",` field·값 또는 assignment를 다음 단계에 전달한다. |
| 10 | "script": "V001__common.sql", | immutable 배포 provenance manifest schema에서 `"script": "V001__common.sql",` field·값 또는 assignment를 다음 단계에 전달한다. |
| 11 | "checksum": "EXAMPLE_FLYWAY_CHECKSUM" | immutable 배포 provenance manifest schema에서 `"checksum": "EXAMPLE_FLYWAY_CHECKSUM"` field·값 또는 assignment를 다음 단계에 전달한다. |
| 12 | }, | 현재 object·array·block 또는 query 범위를 열거나 닫아 구조를 유지한다. |
| 13 | { | 현재 object·array·block 또는 query 범위를 열거나 닫아 구조를 유지한다. |
| 14 | "version": "019", | immutable 배포 provenance manifest schema에서 `"version": "019",` field·값 또는 assignment를 다음 단계에 전달한다. |
| 15 | "script": "V019__audit.sql", | immutable 배포 provenance manifest schema에서 `"script": "V019__audit.sql",` field·값 또는 assignment를 다음 단계에 전달한다. |
| 16 | "checksum": "EXAMPLE_FLYWAY_CHECKSUM" | immutable 배포 provenance manifest schema에서 `"checksum": "EXAMPLE_FLYWAY_CHECKSUM"` field·값 또는 assignment를 다음 단계에 전달한다. |
| 17 | } | 현재 object·array·block 또는 query 범위를 열거나 닫아 구조를 유지한다. |
| 18 | ], | 현재 object·array·block 또는 query 범위를 열거나 닫아 구조를 유지한다. |
| 19 | "dbMigrationInventorySha256": "0000000000000000000000000000000000000000000000000000000000000000", | 현재 file bytes를 64-hex SHA-256 값과 결박하는 field 또는 검사를 다룬다. |
| 20 | "verificationStatus": "MANUAL_REVIEW_REQUIRED" | 자동 shape/hash 검사 뒤에도 사람의 의미 검토가 남았음을 고정한다. |
| 21 | } | 현재 object·array·block 또는 query 범위를 열거나 닫아 구조를 유지한다. |
STEP 07 / 13
기존 수준의 한 줄 읽기·문법 해부
쉬운 설명 다음에 문법과 실행 순서를 정밀하게 읽습니다.
한 줄로 읽기source commit·immutable image digest·실제 Flyway migration inventory hash를 한 manifest에 연결하는 비실행 schema다. 다만 0과 example 값은 실제 배포 증거가 아니다
문법 해부
- JSON object는 source·image·DB inventory field를 한 receipt에 묶는다.
- image는 mutable tag가 아니라 `repository@sha256:digest` 모양으로 고정한다.
실행 순서
- 실제 git SHA를 읽는다.
- registry immutable digest를 읽는다.
- DB schema history를 export한다.
- inventory file hash와 manual status를 manifest에 쓴다.
W22 조각별 정밀 해설
F04-C01 · 원문 1–10줄
- 문법 해부
- 1~10줄의 `원문 1–10줄`을 입력·guard·관찰·cleanup 단계로 나눈다.
- 실제 값 추적
- 항목 전체 흐름에 연결해 `40-char git SHA`을 대조한다. 이 값이 chunk 단독 산출이라는 뜻은 아니다.
- 정상 예
- 정상 예에서는 source 순서와 owner 계약이 일치해 `40-char git SHA`을 관찰한다.
- 틀린 예·반례
- 반례에서는 선행 guard·stable order·cleanup을 생략한다. 동결 경계: 0과 example 값은 실제 배포 증거가 아니다.
- 착각 방지
- `원문 1–10줄`이 항목 전체 Green을 단독 증명한다고 읽지 않는다.
- 하지 않는 일
- 이 chunk가 책임지지 않는 범위: 0과 example 값은 실제 배포 증거가 아니다.
- 다음 연결
- 다음 source chunk의 입력 또는 최종 marker/SQL oracle로 결과를 넘긴다.
F04-C02 · 원문 11–20줄
- 문법 해부
- 11~20줄의 `원문 11–20줄`을 입력·guard·관찰·cleanup 단계로 나눈다.
- 실제 값 추적
- 항목 전체 흐름에 연결해 `repository@sha256`을 대조한다. 이 값이 chunk 단독 산출이라는 뜻은 아니다.
- 정상 예
- 정상 예에서는 source 순서와 owner 계약이 일치해 `repository@sha256`을 관찰한다.
- 틀린 예·반례
- 반례에서는 선행 guard·stable order·cleanup을 생략한다. 동결 경계: V001/V019는 packaged reference 예상값일 뿐 실제 history를 읽어야 한다.
- 착각 방지
- `원문 11–20줄`이 항목 전체 Green을 단독 증명한다고 읽지 않는다.
- 하지 않는 일
- 이 chunk가 책임지지 않는 범위: V001/V019는 packaged reference 예상값일 뿐 실제 history를 읽어야 한다.
- 다음 연결
- 다음 source chunk의 입력 또는 최종 marker/SQL oracle로 결과를 넘긴다.
F04-C03 · 원문 21–21줄
- 문법 해부
- 21~21줄의 `원문 21–21줄`을 입력·guard·관찰·cleanup 단계로 나눈다.
- 실제 값 추적
- 항목 전체 흐름에 연결해 `Java 21`을 대조한다. 이 값이 chunk 단독 산출이라는 뜻은 아니다.
- 정상 예
- 정상 예에서는 source 순서와 owner 계약이 일치해 `Java 21`을 관찰한다.
- 틀린 예·반례
- 반례에서는 선행 guard·stable order·cleanup을 생략한다. 동결 경계: generic hash 검사는 값의 의미를 증명하지 않는다.
- 착각 방지
- `원문 21–21줄`이 항목 전체 Green을 단독 증명한다고 읽지 않는다.
- 하지 않는 일
- 이 chunk가 책임지지 않는 범위: generic hash 검사는 값의 의미를 증명하지 않는다.
- 다음 연결
- 다음 source chunk의 입력 또는 최종 marker/SQL oracle로 결과를 넘긴다.
반례
-
겉보기에는 맞지만 깨지는 예는?
-
latest tag만 기록한다
-
그 상태는 owner·입력·관찰 중 한 칸이 비어 있어.
-
수정한 뒤 같은 source와 hash로 다시 대조해.
STEP 08 / 13
실제 값 따라가기
같은 입력값이 어느 줄을 지나 어떤 결과가 되는지 추적합니다.
| 순서 | 들어온 값 | 코드가 하는 일 | 나온 값·상태 | 경계 |
|---|---|---|---|---|
| F04-T01 source | commit | 40-hex record | gitSha | 0 예시는 미실행 |
| F04-T02 image | registry result | digest bind | repository@sha256 | latest tag 불충분 |
| F04-T03 database | flyway history | inventory+hash | versions/scripts/checksums | 예상 V001/V019와 실제값 구분 |
책임 경계
-
이 항목의 마지막 책임선은?
-
직접 역할은 `immutable 배포 provenance manifest schema`이야.
-
대표 경계는 `latest tag만으로 배포 provenance를 닫지 않는다`이야.
-
정본/비정본 label과 evidence owner까지 확인하면 끝이야.
STEP 09 / 13
GitHub·AWS·PowerShell·PostgreSQL 내부에서 벌어지는 일
GitHub·AWS·PowerShell·PostgreSQL에서 실제로 일어나는 일과 증명 범위를 구분합니다.
commit SHA가 source snapshot을 가리킨다.
미커밋 파일은 포함하지 않는다.digest가 image content 주소가 된다.
signature·SBOM까지 자동 검증하지 않는다.schema history가 실제 적용 version·script·checksum을 가진다.
JSON 예시 목록을 복사하면 live DB proof가 아니다.STEP 10 / 13
흔한 착각과 틀린 예
그럴듯하지만 틀린 해석을 반례로 고칩니다.
❌ latest tag만 기록한다
왜 틀리나 immutable 배포 provenance manifest schema의 owner·관찰·경계 중 적어도 하나를 건너뛴다.
바르게 읽기 실제 git SHA를 읽는다. 그리고 source의 실제 값과 hash를 다시 대조한다.
반례 반례에서는 `0과 example 값은 실제 배포 증거가 아니다` 상태인데도 Green을 주장하게 된다.
❌ git SHA 대신 branch 이름만 쓴다
왜 틀리나 immutable 배포 provenance manifest schema의 owner·관찰·경계 중 적어도 하나를 건너뛴다.
바르게 읽기 registry immutable digest를 읽는다. 그리고 source의 실제 값과 hash를 다시 대조한다.
반례 반례에서는 `V001/V019는 packaged reference 예상값일 뿐 실제 history를 읽어야 한다` 상태인데도 Green을 주장하게 된다.
❌ migration을 오래된 V5로 고정한다
왜 틀리나 immutable 배포 provenance manifest schema의 owner·관찰·경계 중 적어도 하나를 건너뛴다.
바르게 읽기 DB schema history를 export한다. 그리고 source의 실제 값과 hash를 다시 대조한다.
반례 반례에서는 `generic hash 검사는 값의 의미를 증명하지 않는다` 상태인데도 Green을 주장하게 된다.
❌ inventory path 없이 hash만 적는다
왜 틀리나 immutable 배포 provenance manifest schema의 owner·관찰·경계 중 적어도 하나를 건너뛴다.
바르게 읽기 inventory file hash와 manual status를 manifest에 쓴다. 그리고 source의 실제 값과 hash를 다시 대조한다.
반례 반례에서는 `latest tag만으로 배포 provenance를 닫지 않는다` 상태인데도 Green을 주장하게 된다.
❌ 파일 hash가 맞으면 의미도 맞다고 본다
왜 틀리나 immutable 배포 provenance manifest schema의 owner·관찰·경계 중 적어도 하나를 건너뛴다.
바르게 읽기 inventory file hash와 manual status를 manifest에 쓴다. 그리고 source의 실제 값과 hash를 다시 대조한다.
반례 반례에서는 `0과 example 값은 실제 배포 증거가 아니다` 상태인데도 Green을 주장하게 된다.
STEP 11 / 13
이 코드가 보장하지 않는 것
이 코드가 책임지지 않는 일을 분리합니다.
0과 example 값은 실제 배포 증거가 아니다
이 책임을 맡는 곳: 별도 외부/selector 실행V001/V019는 packaged reference 예상값일 뿐 실제 history를 읽어야 한다
이 책임을 맡는 곳: secret·운영 정책generic hash 검사는 값의 의미를 증명하지 않는다
이 책임을 맡는 곳: infrastructure·사람 검토latest tag만으로 배포 provenance를 닫지 않는다
이 책임을 맡는 곳: owner lifecycleSTEP 12 / 13
직접 다시 써보기
뜻 → 조각 → 전체 코드 순서로 다시 씁니다.
1단계 · 뜻부터 복원
다음 역할을 고정값과 미보장 경계까지 말한다: source commit·immutable image digest·실제 Flyway migration inventory hash를 한 manifest에 연결하는 비실행 schema다.
2단계 · 코드 조각 재조립
- 원문 1–10줄
- 원문 11–20줄
- 원문 21–21줄
3단계 · 파일 전체 다시 쓰기
21개 물리 줄을 원본 순서로 복원하고 SHA-256 033ffaf3e3593b697c693a87913886c51fbcfb0b2fd82508215b146e6c421418와 대조한다.
자가 점검
- 원본 source/template bytes를 바꾸지 않았는가?
- 외부 미실행과 local restore Green을 구분했는가?
- secret 원문을 evidence에 남기지 않았는가?
- D7 checked_at 충돌과 사람 검토 경계를 보았는가?
- Q35/Q36을 workbook 정본 답안이라고 부르지 않았는가?
STEP 13 / 13
전체 원본 source
감사로 고정한 전체 source를 가감 없이 확인합니다.
학습용 예시 전체 확인하기 · 정본 답안 아님
{
"_provenance": "학습용 예시 · PDF manifest schema · 정본 답안 아님 · 비실행",
"gitSha": "0000000000000000000000000000000000000000",
"image": "example.invalid/financial-core@sha256:0000000000000000000000000000000000000000000000000000000000000000",
"java": "21",
"springBoot": "4.1.0",
"dbMigrations": [
{
"version": "001",
"script": "V001__common.sql",
"checksum": "EXAMPLE_FLYWAY_CHECKSUM"
},
{
"version": "019",
"script": "V019__audit.sql",
"checksum": "EXAMPLE_FLYWAY_CHECKSUM"
}
],
"dbMigrationInventorySha256": "0000000000000000000000000000000000000000000000000000000000000000",
"verificationStatus": "MANUAL_REVIEW_REQUIRED"
}
05RDS 5단 진단 — identity→secret→network→migration→readiness
illustrative/shell/W22-D5-rds-connectivity.sh
학습용 예시 · PDF shell 학습 골격 · 정본 답안 아님 · 그대로 실행 금지 · 학습용 예시 · 정본 답안 아님 · W22-F0514줄 연결14줄 번역2 chunks
RDS 5단 진단 — identity→secret→network→migration→readiness
illustrative/shell/W22-D5-rds-connectivity.sh
학습용 예시 · PDF shell 학습 골격 · 정본 답안 아님 · 그대로 실행 금지 · 학습용 예시 · 정본 답안 아님 · W22-F05STEP 01 / 13
오늘 이 코드에서 해결할 문제
무엇을 이해해야 하는지 질문부터 잡습니다.
RDS 연결 문제를 identity→secret ARN→network→migration→readiness 순서로 분리하는 PDF 학습 runbook이다.
- `caller identity`은 어느 줄에서 생길까?
- 입력→guard→관찰→cleanup 순서는 무엇인가?
- local owner와 external human review는 누구인가?
- 직접 관찰하지 않은 Green은 무엇인가?
- 반례는 `그대로 실행할 완전한 script가 아니다`이라는 경계와 어떻게 연결되는가?
caller identityparameter ARN onlypg_isready 5432flywayInforeadinessSTEP 02 / 13
아주 짧게: 이 코드는 왜 필요할까?
웹소설 대신 이 코드가 필요한 이유만 두 문단으로 쉽게 봅니다.
STARRY가 GitHub run표·AWS 출입증·DB 복구 영수증·SQL 결과표를 서로 다른 칸에 놓는다.
RDS 5단 진단 — identity→secret→network→migration→readiness ― 증거 흐름으로 바꾸기
RDS 연결 문제를 identity→secret ARN→network→migration→readiness 순서로 분리하는 PDF 학습 runbook이다.
핵심값 caller identity, parameter ARN only, pg_isready 5432, flywayInfo, readiness을 원본 줄로 따라가되, `그대로 실행할 완전한 script가 아니다`까지 함께 표시해 Green 범위를 부풀리지 않는다.
딱 여기까지만 비유는 owner와 순서를 기억하게 할 뿐 외부 실행·AWS 계정 상태·PostgreSQL restore·SQL 결과를 자동 증명하지 않는다.
STEP 03 / 13
초등학생도 이해하는 설명
생활 비유와 실제 코드의 경계를 함께 확인합니다.
원문 1–10줄
1~10줄을 한 덩어리로 읽어 1번째 움직임을 본다. RDS 연결 문제를 identity→secret ARN→network→migration→readiness 순서로 분리하는 PDF 학습 runbook이다.
- 코드 연결
1~10줄- 비유
- 출입증(identity), 복도(network), 잠금번호(secret), 방 배치(schema), 영업등(readiness)을 차례로 보는 장애 진단 사다리
- 비유의 끝
- 그대로 실행할 완전한 script가 아니다
원문 11–14줄
11~14줄을 한 덩어리로 읽어 2번째 움직임을 본다. RDS 연결 문제를 identity→secret ARN→network→migration→readiness 순서로 분리하는 PDF 학습 runbook이다.
- 코드 연결
11~14줄- 비유
- 출입증(identity), 복도(network), 잠금번호(secret), 방 배치(schema), 영업등(readiness)을 차례로 보는 장애 진단 사다리
- 비유의 끝
- secret Value를 출력하지 않는다
문제의 첫 장면
-
첫 고정값은 `caller identity` 맞아?
-
RDS 연결 문제를 identity→secret ARN→network→migration→readiness 순서로 분리하는 PDF 학습 runbook이다.
-
원문에서 `caller identity`이 생기는 위치를 찾자.
-
그리고 `그대로 실행할 완전한 script가 아니다`도 같이 적어.
입력에서 결과까지
-
`parameter ARN only`은 언제 생겨?
-
caller identity를 확인한다. → secret ARN과 권한 경계를 확인한다.
-
private host에서 5432를 확인한다. → migration 뒤 readiness를 확인한다.
-
관찰값과 `secret Value를 출력하지 않는다`을 분리하면 돼.
STEP 04 / 13
비유 ↔ 코드 전체 연결표
감사 규칙상 연결 대상인 원본 14줄을 빠짐없이 연결합니다.
| 줄 | 정확한 원본 줄 | STARRY 비유 | 실제 뜻·입력·결과·한계 |
|---|---|---|---|
| 1줄F05-L01 | #!/ |
출입증(identity), 복도(network), 잠금번호(secret), 방 배치(schema), 영업등(readiness)을 차례로 보는 장애 진단 사다리 | 이 source의 비정본 provenance, 가정, 반례, 또는 실행 경계를 사람이 확인할 주석이다.
|
| 2줄F05-L02 | # 학습용 예시 · PDF 연결 순서 template · 정본 답안 아님 · 그대로 실행 금지 |
출입증(identity), 복도(network), 잠금번호(secret), 방 배치(schema), 영업등(readiness)을 차례로 보는 장애 진단 사다리 | 이 source의 비정본 provenance, 가정, 반례, 또는 실행 경계를 사람이 확인할 주석이다.
|
| 3줄F05-L03 | # 1. |
출입증(identity), 복도(network), 잠금번호(secret), 방 배치(schema), 영업등(readiness)을 차례로 보는 장애 진단 사다리 | 이 source의 비정본 provenance, 가정, 반례, 또는 실행 경계를 사람이 확인할 주석이다.
|
| 4줄F05-L04 | aws sts get-caller-identity |
출입증(identity), 복도(network), 잠금번호(secret), 방 배치(schema), 영업등(readiness)을 차례로 보는 장애 진단 사다리 | 현재 AWS session이 의도한 caller인지 먼저 관찰한다.
|
| 5줄F05-L05 | # 2. |
출입증(identity), 복도(network), 잠금번호(secret), 방 배치(schema), 영업등(readiness)을 차례로 보는 장애 진단 사다리 | 이 source의 비정본 provenance, 가정, 반례, 또는 실행 경계를 사람이 확인할 주석이다.
|
| 6줄F05-L06 | aws ssm get-parameter --name / |
출입증(identity), 복도(network), 잠금번호(secret), 방 배치(schema), 영업등(readiness)을 차례로 보는 장애 진단 사다리 | inbound SSH 없이 관리 session 또는 secret metadata를 다루는 AWS 경계를 나타낸다.
|
| 7줄F05-L07 | # 3. |
출입증(identity), 복도(network), 잠금번호(secret), 방 배치(schema), 영업등(readiness)을 차례로 보는 장애 진단 사다리 | private PostgreSQL 5432와 application SG 사이의 DB 경계를 표현한다.
|
| 8줄F05-L08 | pg_isready -h private-rds-endpoint. |
출입증(identity), 복도(network), 잠금번호(secret), 방 배치(schema), 영업등(readiness)을 차례로 보는 장애 진단 사다리 | private PostgreSQL 5432와 application SG 사이의 DB 경계를 표현한다.
|
| 9줄F05-L09 | # 4. |
출입증(identity), 복도(network), 잠금번호(secret), 방 배치(schema), 영업등(readiness)을 차례로 보는 장애 진단 사다리 | 이 source의 비정본 provenance, 가정, 반례, 또는 실행 경계를 사람이 확인할 주석이다.
|
| 10줄F05-L10 | . |
출입증(identity), 복도(network), 잠금번호(secret), 방 배치(schema), 영업등(readiness)을 차례로 보는 장애 진단 사다리 | application traffic 전에 migration 상태를 읽는 학습 단계다.
|
| 11줄F05-L11 | # 5. |
출입증(identity), 복도(network), 잠금번호(secret), 방 배치(schema), 영업등(readiness)을 차례로 보는 장애 진단 사다리 | migration과 dependency가 준비된 뒤 traffic 수락 상태를 확인한다.
|
| 12줄F05-L12 | curl --fail --silent http: |
출입증(identity), 복도(network), 잠금번호(secret), 방 배치(schema), 영업등(readiness)을 차례로 보는 장애 진단 사다리 | migration과 dependency가 준비된 뒤 traffic 수락 상태를 확인한다.
|
| 13줄F05-L13 | # timeout은 route·DNS·SG 단계, |
출입증(identity), 복도(network), 잠금번호(secret), 방 배치(schema), 영업등(readiness)을 차례로 보는 장애 진단 사다리 | 이 source의 비정본 provenance, 가정, 반례, 또는 실행 경계를 사람이 확인할 주석이다.
|
| 14줄F05-L14 | # secret 원문, |
출입증(identity), 복도(network), 잠금번호(secret), 방 배치(schema), 영업등(readiness)을 차례로 보는 장애 진단 사다리 | 이 source의 비정본 provenance, 가정, 반례, 또는 실행 경계를 사람이 확인할 주석이다.
|
Green 범위
-
marker나 파일이 보이면 전부 성공이야?
-
아니. source가 직접 검증한 범위만 말해야 해.
-
직접 연결되는 대표 값은 `readiness`이야.
-
`private host 밖에서 RDS를 공개하지 않는다`는 별도 증거가 필요해.
STEP 05 / 13
원본 코드 조각
원본을 2개 의미 조각으로 나누어 그대로 확인합니다.
파일을 한꺼번에 외우지 않고 실행 의미가 이어지는 작은 조각으로 봅니다. 아래 코드는 prompt·fixture·가정을 밝힌 학습용 예시 source이며, 제공 정본 답안이 아닙니다.
#!/usr/bin/env bash
# 학습용 예시 · PDF 연결 순서 template · 정본 답안 아님 · 그대로 실행 금지
# 1. identity: 현재 AWS caller가 의도한 deploy/app role인지 확인한다.
aws sts get-caller-identity
# 2. secret boundary: decrypted Value를 출력하지 않고 parameter ARN만 확인한다.
aws ssm get-parameter --name /fcl/prod/db/password --query Parameter.ARN
# 3. network: private app host에서만 private RDS endpoint와 5432 도달성을 확인한다.
pg_isready -h private-rds-endpoint.internal -p 5432
# 4. migration: Flyway info와 실제 schema history의 version·script·checksum을 대조한다.
./gradlew flywayInfo
# 5. readiness: migration 성공 뒤에만 application traffic readiness를 확인한다.
curl --fail --silent http://127.0.0.1:8080/actuator/health/readiness
# timeout은 route·DNS·SG 단계, password authentication failed는 secret·user·DB name 단계를 먼저 본다.
# secret 원문, account ID, endpoint 전체는 evidence에 저장하지 않는다.
STEP 06 / 13
코드 한 줄씩 한국어로 번역
비어 있지 않은 14줄을 모두 한국어로 옮깁니다.
비어 있지 않은 원본 줄은 하나도 생략하지 않습니다.
| 줄 | 원본 | 한국어 번역 |
|---|---|---|
| 1 | #!/usr/bin/env bash | 이 source의 비정본 provenance, 가정, 반례, 또는 실행 경계를 사람이 확인할 주석이다. |
| 2 | # 학습용 예시 · PDF 연결 순서 template · 정본 답안 아님 · 그대로 실행 금지 | 이 source의 비정본 provenance, 가정, 반례, 또는 실행 경계를 사람이 확인할 주석이다. |
| 3 | # 1. identity: 현재 AWS caller가 의도한 deploy/app role인지 확인한다. | 이 source의 비정본 provenance, 가정, 반례, 또는 실행 경계를 사람이 확인할 주석이다. |
| 4 | aws sts get-caller-identity | 현재 AWS session이 의도한 caller인지 먼저 관찰한다. |
| 5 | # 2. secret boundary: decrypted Value를 출력하지 않고 parameter ARN만 확인한다. | 이 source의 비정본 provenance, 가정, 반례, 또는 실행 경계를 사람이 확인할 주석이다. |
| 6 | aws ssm get-parameter --name /fcl/prod/db/password --query Parameter.ARN | inbound SSH 없이 관리 session 또는 secret metadata를 다루는 AWS 경계를 나타낸다. |
| 7 | # 3. network: private app host에서만 private RDS endpoint와 5432 도달성을 확인한다. | private PostgreSQL 5432와 application SG 사이의 DB 경계를 표현한다. |
| 8 | pg_isready -h private-rds-endpoint.internal -p 5432 | private PostgreSQL 5432와 application SG 사이의 DB 경계를 표현한다. |
| 9 | # 4. migration: Flyway info와 실제 schema history의 version·script·checksum을 대조한다. | 이 source의 비정본 provenance, 가정, 반례, 또는 실행 경계를 사람이 확인할 주석이다. |
| 10 | ./gradlew flywayInfo | application traffic 전에 migration 상태를 읽는 학습 단계다. |
| 11 | # 5. readiness: migration 성공 뒤에만 application traffic readiness를 확인한다. | migration과 dependency가 준비된 뒤 traffic 수락 상태를 확인한다. |
| 12 | curl --fail --silent http://127.0.0.1:8080/actuator/health/readiness | migration과 dependency가 준비된 뒤 traffic 수락 상태를 확인한다. |
| 13 | # timeout은 route·DNS·SG 단계, password authentication failed는 secret·user·DB name 단계를 먼저 본다. | 이 source의 비정본 provenance, 가정, 반례, 또는 실행 경계를 사람이 확인할 주석이다. |
| 14 | # secret 원문, account ID, endpoint 전체는 evidence에 저장하지 않는다. | 이 source의 비정본 provenance, 가정, 반례, 또는 실행 경계를 사람이 확인할 주석이다. |
STEP 07 / 13
기존 수준의 한 줄 읽기·문법 해부
쉬운 설명 다음에 문법과 실행 순서를 정밀하게 읽습니다.
한 줄로 읽기RDS 연결 문제를 identity→secret ARN→network→migration→readiness 순서로 분리하는 PDF 학습 runbook이다. 다만 그대로 실행할 완전한 script가 아니다
문법 해부
- 각 명령은 서로 다른 실패 layer를 관찰하며 앞 단계 성공을 뒤 단계 성공으로 확대하지 않는다.
- `--query Parameter.ARN`은 decrypted secret Value 대신 식별자만 읽는다.
실행 순서
- caller identity를 확인한다.
- secret ARN과 권한 경계를 확인한다.
- private host에서 5432를 확인한다.
- migration 뒤 readiness를 확인한다.
W22 조각별 정밀 해설
F05-C01 · 원문 1–10줄
- 문법 해부
- 1~10줄의 `원문 1–10줄`을 입력·guard·관찰·cleanup 단계로 나눈다.
- 실제 값 추적
- 항목 전체 흐름에 연결해 `caller identity`을 대조한다. 이 값이 chunk 단독 산출이라는 뜻은 아니다.
- 정상 예
- 정상 예에서는 source 순서와 owner 계약이 일치해 `caller identity`을 관찰한다.
- 틀린 예·반례
- 반례에서는 선행 guard·stable order·cleanup을 생략한다. 동결 경계: 그대로 실행할 완전한 script가 아니다.
- 착각 방지
- `원문 1–10줄`이 항목 전체 Green을 단독 증명한다고 읽지 않는다.
- 하지 않는 일
- 이 chunk가 책임지지 않는 범위: 그대로 실행할 완전한 script가 아니다.
- 다음 연결
- 다음 source chunk의 입력 또는 최종 marker/SQL oracle로 결과를 넘긴다.
F05-C02 · 원문 11–14줄
- 문법 해부
- 11~14줄의 `원문 11–14줄`을 입력·guard·관찰·cleanup 단계로 나눈다.
- 실제 값 추적
- 항목 전체 흐름에 연결해 `parameter ARN only`을 대조한다. 이 값이 chunk 단독 산출이라는 뜻은 아니다.
- 정상 예
- 정상 예에서는 source 순서와 owner 계약이 일치해 `parameter ARN only`을 관찰한다.
- 틀린 예·반례
- 반례에서는 선행 guard·stable order·cleanup을 생략한다. 동결 경계: secret Value를 출력하지 않는다.
- 착각 방지
- `원문 11–14줄`이 항목 전체 Green을 단독 증명한다고 읽지 않는다.
- 하지 않는 일
- 이 chunk가 책임지지 않는 범위: secret Value를 출력하지 않는다.
- 다음 연결
- 다음 source chunk의 입력 또는 최종 marker/SQL oracle로 결과를 넘긴다.
반례
-
겉보기에는 맞지만 깨지는 예는?
-
timeout과 password authentication failed를 같은 문제로 본다
-
그 상태는 owner·입력·관찰 중 한 칸이 비어 있어.
-
수정한 뒤 같은 source와 hash로 다시 대조해.
STEP 08 / 13
실제 값 따라가기
같은 입력값이 어느 줄을 지나 어떤 결과가 되는지 추적합니다.
| 순서 | 들어온 값 | 코드가 하는 일 | 나온 값·상태 | 경계 |
|---|---|---|---|---|
| F05-T01 identity | AWS session | sts | caller | account 전체 노출 주의 |
| F05-T02 connectivity | private endpoint | pg_isready | accepting/timeout | schema는 모름 |
| F05-T03 application | migrated DB | readiness GET | UP | secret 원문 저장 금지 |
책임 경계
-
이 항목의 마지막 책임선은?
-
직접 역할은 `RDS 연결 단계별 진단 template`이야.
-
대표 경계는 `migration 성공 전 traffic readiness를 열지 않는다`이야.
-
정본/비정본 label과 evidence owner까지 확인하면 끝이야.
STEP 09 / 13
GitHub·AWS·PowerShell·PostgreSQL 내부에서 벌어지는 일
GitHub·AWS·PowerShell·PostgreSQL에서 실제로 일어나는 일과 증명 범위를 구분합니다.
timeout의 network 경로를 구성한다.
auth failure와 구분한다.도달 뒤 user/password/DB name을 확인한다.
log에 password를 쓰지 않는다.migration 성공 뒤 readiness를 traffic 신호로 쓴다.
migration 실패 중 traffic을 받지 않는다.STEP 10 / 13
흔한 착각과 틀린 예
그럴듯하지만 틀린 해석을 반례로 고칩니다.
❌ timeout과 password authentication failed를 같은 문제로 본다
왜 틀리나 RDS 연결 단계별 진단 template의 owner·관찰·경계 중 적어도 하나를 건너뛴다.
바르게 읽기 caller identity를 확인한다. 그리고 source의 실제 값과 hash를 다시 대조한다.
반례 반례에서는 `그대로 실행할 완전한 script가 아니다` 상태인데도 Green을 주장하게 된다.
❌ SSM parameter Value를 evidence에 출력한다
왜 틀리나 RDS 연결 단계별 진단 template의 owner·관찰·경계 중 적어도 하나를 건너뛴다.
바르게 읽기 secret ARN과 권한 경계를 확인한다. 그리고 source의 실제 값과 hash를 다시 대조한다.
반례 반례에서는 `secret Value를 출력하지 않는다` 상태인데도 Green을 주장하게 된다.
❌ 노트북에서 private RDS를 직접 공개한다
왜 틀리나 RDS 연결 단계별 진단 template의 owner·관찰·경계 중 적어도 하나를 건너뛴다.
바르게 읽기 private host에서 5432를 확인한다. 그리고 source의 실제 값과 hash를 다시 대조한다.
반례 반례에서는 `private host 밖에서 RDS를 공개하지 않는다` 상태인데도 Green을 주장하게 된다.
❌ Flyway 실패인데 readiness를 연다
왜 틀리나 RDS 연결 단계별 진단 template의 owner·관찰·경계 중 적어도 하나를 건너뛴다.
바르게 읽기 migration 뒤 readiness를 확인한다. 그리고 source의 실제 값과 hash를 다시 대조한다.
반례 반례에서는 `migration 성공 전 traffic readiness를 열지 않는다` 상태인데도 Green을 주장하게 된다.
❌ 명령 조각을 완전 자동 script라고 부른다
왜 틀리나 RDS 연결 단계별 진단 template의 owner·관찰·경계 중 적어도 하나를 건너뛴다.
바르게 읽기 migration 뒤 readiness를 확인한다. 그리고 source의 실제 값과 hash를 다시 대조한다.
반례 반례에서는 `그대로 실행할 완전한 script가 아니다` 상태인데도 Green을 주장하게 된다.
STEP 11 / 13
이 코드가 보장하지 않는 것
이 코드가 책임지지 않는 일을 분리합니다.
그대로 실행할 완전한 script가 아니다
이 책임을 맡는 곳: 별도 외부/selector 실행secret Value를 출력하지 않는다
이 책임을 맡는 곳: secret·운영 정책private host 밖에서 RDS를 공개하지 않는다
이 책임을 맡는 곳: infrastructure·사람 검토migration 성공 전 traffic readiness를 열지 않는다
이 책임을 맡는 곳: owner lifecycleSTEP 12 / 13
직접 다시 써보기
뜻 → 조각 → 전체 코드 순서로 다시 씁니다.
1단계 · 뜻부터 복원
다음 역할을 고정값과 미보장 경계까지 말한다: RDS 연결 문제를 identity→secret ARN→network→migration→readiness 순서로 분리하는 PDF 학습 runbook이다.
2단계 · 코드 조각 재조립
- 원문 1–10줄
- 원문 11–14줄
3단계 · 파일 전체 다시 쓰기
14개 물리 줄을 원본 순서로 복원하고 SHA-256 b88ed6cf171060bd793fd57c682ad0444ce5ace14fd16ba0423c6ba42e312006와 대조한다.
자가 점검
- 원본 source/template bytes를 바꾸지 않았는가?
- 외부 미실행과 local restore Green을 구분했는가?
- secret 원문을 evidence에 남기지 않았는가?
- D7 checked_at 충돌과 사람 검토 경계를 보았는가?
- Q35/Q36을 workbook 정본 답안이라고 부르지 않았는가?
STEP 13 / 13
전체 원본 source
감사로 고정한 전체 source를 가감 없이 확인합니다.
학습용 예시 전체 확인하기 · 정본 답안 아님
#!/usr/bin/env bash
# 학습용 예시 · PDF 연결 순서 template · 정본 답안 아님 · 그대로 실행 금지
# 1. identity: 현재 AWS caller가 의도한 deploy/app role인지 확인한다.
aws sts get-caller-identity
# 2. secret boundary: decrypted Value를 출력하지 않고 parameter ARN만 확인한다.
aws ssm get-parameter --name /fcl/prod/db/password --query Parameter.ARN
# 3. network: private app host에서만 private RDS endpoint와 5432 도달성을 확인한다.
pg_isready -h private-rds-endpoint.internal -p 5432
# 4. migration: Flyway info와 실제 schema history의 version·script·checksum을 대조한다.
./gradlew flywayInfo
# 5. readiness: migration 성공 뒤에만 application traffic readiness를 확인한다.
curl --fail --silent http://127.0.0.1:8080/actuator/health/readiness
# timeout은 route·DNS·SG 단계, password authentication failed는 secret·user·DB name 단계를 먼저 본다.
# secret 원문, account ID, endpoint 전체는 evidence에 저장하지 않는다.
06run-w22-restore.ps1 — disposable restore 3·120·0 owner
scripts/run-w22-restore.ps1
원문 정본 · 완전한 packaged PowerShell source · 정본 · W22-F06122줄 연결122줄 번역12 chunks
run-w22-restore.ps1 — disposable restore 3·120·0 owner
scripts/run-w22-restore.ps1
원문 정본 · 완전한 packaged PowerShell source · 정본 · W22-F06STEP 01 / 13
오늘 이 코드에서 해결할 문제
무엇을 이해해야 하는지 질문부터 잡습니다.
고정 3행을 별도 DB에 dump/restore해 3·120·0과 cleanup을 검증하고 canonical restore-result.json을 atomic publish하는 W22 packaged owner다.
- `row_count=3`은 어느 줄에서 생길까?
- 입력→guard→관찰→cleanup 순서는 무엇인가?
- local owner와 external human review는 누구인가?
- 직접 관찰하지 않은 Green은 무엇인가?
- 반례는 `production RPO/RTO 보장이 아니다`이라는 경계와 어떻게 연결되는가?
row_count=3ledger_sum=120mismatch=0cleanup=1W22_RESTORE_GREENSTEP 02 / 13
아주 짧게: 이 코드는 왜 필요할까?
웹소설 대신 이 코드가 필요한 이유만 두 문단으로 쉽게 봅니다.
STARRY가 GitHub run표·AWS 출입증·DB 복구 영수증·SQL 결과표를 서로 다른 칸에 놓는다.
run-w22-restore.ps1 — disposable restore 3·120·0 owner ― 증거 흐름으로 바꾸기
고정 3행을 별도 DB에 dump/restore해 3·120·0과 cleanup을 검증하고 canonical restore-result.json을 atomic publish하는 W22 packaged owner다.
핵심값 row_count=3, ledger_sum=120, mismatch=0, cleanup=1, W22_RESTORE_GREEN을 원본 줄로 따라가되, `production RPO/RTO 보장이 아니다`까지 함께 표시해 Green 범위를 부풀리지 않는다.
딱 여기까지만 비유는 owner와 순서를 기억하게 할 뿐 외부 실행·AWS 계정 상태·PostgreSQL restore·SQL 결과를 자동 증명하지 않는다.
STEP 03 / 13
초등학생도 이해하는 설명
생활 비유와 실제 코드의 경계를 함께 확인합니다.
원문 1–12줄
1~12줄을 한 덩어리로 읽어 1번째 움직임을 본다. 고정 3행을 별도 DB에 dump/restore해 3·120·0과 cleanup을 검증하고 canonical restore-result.json을 atomic publish하는 W22 packaged owner다.
- 코드 연결
1~12줄- 비유
- 감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련
- 비유의 끝
- production RPO/RTO 보장이 아니다
원문 13–24줄
13~24줄을 한 덩어리로 읽어 2번째 움직임을 본다. 고정 3행을 별도 DB에 dump/restore해 3·120·0과 cleanup을 검증하고 canonical restore-result.json을 atomic publish하는 W22 packaged owner다.
- 코드 연결
13~24줄- 비유
- 감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련
- 비유의 끝
- run-w42-restore-drill.ps1에 transitive 의존한다
원문 25–36줄
25~36줄을 한 덩어리로 읽어 3번째 움직임을 본다. 고정 3행을 별도 DB에 dump/restore해 3·120·0과 cleanup을 검증하고 canonical restore-result.json을 atomic publish하는 W22 packaged owner다.
- 코드 연결
25~36줄- 비유
- 감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련
- 비유의 끝
- 허용 target DB 이름만 쓴다
문제의 첫 장면
-
첫 고정값은 `row_count=3` 맞아?
-
고정 3행을 별도 DB에 dump/restore해 3·120·0과 cleanup을 검증하고 canonical restore-result.json을 atomic publish하는 W22 packaged owner다.
-
원문에서 `row_count=3`이 생기는 위치를 찾자.
-
그리고 `production RPO/RTO 보장이 아니다`도 같이 적어.
입력에서 결과까지
-
`ledger_sum=120`은 언제 생겨?
-
allowlist와 transitive tool을 검사한다. → Compose 또는 caller container를 선택한다.
-
W42 restore 결과 3·120·0을 재검증한다. → cleanup 뒤 restore-result.json을 atomic publish한다.
-
관찰값과 `run-w42-restore-drill.ps1에 transitive 의존한다`을 분리하면 돼.
STEP 04 / 13
비유 ↔ 코드 전체 연결표
감사 규칙상 연결 대상인 원본 122줄을 빠짐없이 연결합니다.
| 줄 | 정확한 원본 줄 | STARRY 비유 | 실제 뜻·입력·결과·한계 |
|---|---|---|---|
| 1줄F06-L01 | param( |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | W22 restore runner의 호출 parameter 계약을 연다.
|
| 2줄F06-L02 | [ |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 허용 실행 mode를 Compose와 Container 두 값으로 제한한다.
|
| 3줄F06-L03 | [ |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 정본 W22 disposable restore evidence producer에서 `[string]$ComposeProject = 'w22-restore-lab',` field·값 또는 assignment를 다음 단계에 전달한다.
|
| 4줄F06-L04 | [ |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 정본 W22 disposable restore evidence producer에서 `[string]$ContainerName = '',` field·값 또는 assignment를 다음 단계에 전달한다.
|
| 5줄F06-L05 | [ |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 정본 W22 disposable restore evidence producer에서 `[string]$EvidenceDir = 'evidence/w22',` field·값 또는 assignment를 다음 단계에 전달한다.
|
| 6줄F06-L06 | [ |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | disposable restore target 이름과 exact allowlist를 다룬다.
|
| 7줄F06-L07 | ) |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 현재 object·array·block 또는 query 범위를 열거나 닫아 구조를 유지한다.
|
| 9줄F06-L09 | Set-StrictMode -Version Latest |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 미정의 변수 등 PowerShell 오류를 조기에 드러낸다.
|
| 10줄F06-L10 | $ErrorActionPreference = |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | PowerShell cmdlet 오류를 terminating error로 처리한다.
|
| 12줄F06-L12 | if ( |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | disposable restore target 이름과 exact allowlist를 다룬다.
|
| 13줄F06-L13 | throw 'W22 disposable target allowlist violation' |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 정본 W22 disposable restore evidence producer의 13번째 원문을 앞 guard와 뒤 관찰값 사이에 연결한다.
|
| 14줄F06-L14 | } |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 현재 object·array·block 또는 query 범위를 열거나 닫아 구조를 유지한다.
|
| 16줄F06-L16 | $root = |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 정본 W22 disposable restore evidence producer에서 `$root = Split-Path -Parent $PSScriptRoot` field·값 또는 assignment를 다음 단계에 전달한다.
|
| 17줄F06-L17 | $evidence = |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 정본 W22 disposable restore evidence producer에서 `$evidence = if ([IO.Path]::IsPathRooted($Evidenc` field·값 또는 assignment를 다음 단계에 전달한다.
|
| 18줄F06-L18 | [ |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 정본 W22 disposable restore evidence producer에서 `[IO.Path]::GetFullPath($EvidenceDir)` field·값 또는 assignment를 다음 단계에 전달한다.
|
| 19줄F06-L19 | } else { |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 정본 W22 disposable restore evidence producer의 19번째 원문을 앞 guard와 뒤 관찰값 사이에 연결한다.
|
| 20줄F06-L20 | [ |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 정본 W22 disposable restore evidence producer에서 `[IO.Path]::GetFullPath((Join-Path $root $Evidenc` field·값 또는 assignment를 다음 단계에 전달한다.
|
| 21줄F06-L21 | } |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 현재 object·array·block 또는 query 범위를 열거나 닫아 구조를 유지한다.
|
| 22줄F06-L22 | $tool = |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 완전한 restore 수행을 맡는 packaged W42 transitive tool을 찾는다.
|
| 23줄F06-L23 | $compose = |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 정본 W22 disposable restore evidence producer에서 `$compose = Join-Path $root 'compose.yaml'` field·값 또는 assignment를 다음 단계에 전달한다.
|
| 24줄F06-L24 | $ownedCompose = |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 정본 W22 disposable restore evidence producer에서 `$ownedCompose = $false` field·값 또는 assignment를 다음 단계에 전달한다.
|
| 25줄F06-L25 | $composeCleanup = |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | source/target DB와 소유 resource 정리 결과를 evidence에 묶는다.
|
| 26줄F06-L26 | $failure = |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 정본 W22 disposable restore evidence producer에서 `$failure = $null` field·값 또는 assignment를 다음 단계에 전달한다.
|
| 27줄F06-L27 | $body = |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 정본 W22 disposable restore evidence producer에서 `$body = $null` field·값 또는 assignment를 다음 단계에 전달한다.
|
| 29줄F06-L29 | if ( |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 선행 invariant가 깨졌을 때 다음 단계로 진행하지 않도록 fail-closed guard를 적용한다.
|
| 30줄F06-L30 | throw 'W22 transitive W42 tool missing' |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 정본 W22 disposable restore evidence producer의 30번째 원문을 앞 guard와 뒤 관찰값 사이에 연결한다.
|
| 31줄F06-L31 | } |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 현재 object·array·block 또는 query 범위를 열거나 닫아 구조를 유지한다.
|
| 33줄F06-L33 | try { |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 정본 W22 disposable restore evidence producer의 33번째 원문을 앞 guard와 뒤 관찰값 사이에 연결한다.
|
| 34줄F06-L34 | if ( |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 선행 invariant가 깨졌을 때 다음 단계로 진행하지 않도록 fail-closed guard를 적용한다.
|
| 35줄F06-L35 | if ( |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 선행 invariant가 깨졌을 때 다음 단계로 진행하지 않도록 fail-closed guard를 적용한다.
|
| 36줄F06-L36 | if ( |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 선행 invariant가 깨졌을 때 다음 단계로 진행하지 않도록 fail-closed guard를 적용한다.
|
| 37줄F06-L37 | $env: |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 정본 W22 disposable restore evidence producer에서 `$env:FCL_DB_PASSWORD = 'w22-disposable-password'` field·값 또는 assignment를 다음 단계에 전달한다.
|
| 38줄F06-L38 | } |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 현재 object·array·block 또는 query 범위를 열거나 닫아 구조를 유지한다.
|
| 39줄F06-L39 | # Own the unique Compose project before startup so a partial `up` |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 이 source의 비정본 provenance, 가정, 반례, 또는 실행 경계를 사람이 확인할 주석이다.
|
| 40줄F06-L40 | # failure still reaches finally/ |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 이 source의 비정본 provenance, 가정, 반례, 또는 실행 경계를 사람이 확인할 주석이다.
|
| 41줄F06-L41 | $ownedCompose = |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 정본 W22 disposable restore evidence producer에서 `$ownedCompose = $true` field·값 또는 assignment를 다음 단계에 전달한다.
|
| 42줄F06-L42 | & docker compose -f $compose -p $ComposeProject up -d --wait db |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | W22가 소유한 DB Compose project를 시작하거나 finally에서 정리한다.
|
| 43줄F06-L43 | if ( |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 선행 invariant가 깨졌을 때 다음 단계로 진행하지 않도록 fail-closed guard를 적용한다.
|
| 44줄F06-L44 | $ContainerName = |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | W22가 소유한 DB Compose project를 시작하거나 finally에서 정리한다.
|
| 45줄F06-L45 | } elseif ( |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 정본 W22 disposable restore evidence producer에서 `} elseif ([string]::IsNullOrWhiteSpace($Containe` field·값 또는 assignment를 다음 단계에 전달한다.
|
| 46줄F06-L46 | throw 'W22 Container mode requires ContainerName' |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 정본 W22 disposable restore evidence producer의 46번째 원문을 앞 guard와 뒤 관찰값 사이에 연결한다.
|
| 47줄F06-L47 | } |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 현재 object·array·block 또는 query 범위를 열거나 닫아 구조를 유지한다.
|
| 48줄F06-L48 | if ( |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 선행 invariant가 깨졌을 때 다음 단계로 진행하지 않도록 fail-closed guard를 적용한다.
|
| 49줄F06-L49 | throw 'W22 container resolution failed' |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 정본 W22 disposable restore evidence producer의 49번째 원문을 앞 guard와 뒤 관찰값 사이에 연결한다.
|
| 50줄F06-L50 | } |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 현재 object·array·block 또는 query 범위를 열거나 닫아 구조를 유지한다.
|
| 52줄F06-L52 | $output = |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 정본 W22 disposable restore evidence producer에서 `$output = @(` field·값 또는 assignment를 다음 단계에 전달한다.
|
| 53줄F06-L53 | & powershell. |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 정본 W22 disposable restore evidence producer의 53번째 원문을 앞 guard와 뒤 관찰값 사이에 연결한다.
|
| 54줄F06-L54 | -Mode Container ` |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 정본 W22 disposable restore evidence producer의 54번째 원문을 앞 guard와 뒤 관찰값 사이에 연결한다.
|
| 55줄F06-L55 | -ContainerName $ContainerName ` |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 정본 W22 disposable restore evidence producer의 55번째 원문을 앞 guard와 뒤 관찰값 사이에 연결한다.
|
| 56줄F06-L56 | -AdminDatabase financial_core ` |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 정본 W22 disposable restore evidence producer의 56번째 원문을 앞 guard와 뒤 관찰값 사이에 연결한다.
|
| 57줄F06-L57 | -Username app ` |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 정본 W22 disposable restore evidence producer의 57번째 원문을 앞 guard와 뒤 관찰값 사이에 연결한다.
|
| 58줄F06-L58 | -TargetDb $TargetDb ` |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | disposable restore target 이름과 exact allowlist를 다룬다.
|
| 59줄F06-L59 | -EvidenceDir $evidence 2>&1 |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 정본 W22 disposable restore evidence producer의 59번째 원문을 앞 guard와 뒤 관찰값 사이에 연결한다.
|
| 60줄F06-L60 | ) |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 현재 object·array·block 또는 query 범위를 열거나 닫아 구조를 유지한다.
|
| 61줄F06-L61 | $nativeExit = |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 정본 W22 disposable restore evidence producer에서 `$nativeExit = $LASTEXITCODE` field·값 또는 assignment를 다음 단계에 전달한다.
|
| 62줄F06-L62 | if ( |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 선행 invariant가 깨졌을 때 다음 단계로 진행하지 않도록 fail-closed guard를 적용한다.
|
| 63줄F06-L63 | throw "W22 restore native exit= |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 정본 W22 disposable restore evidence producer에서 `throw "W22 restore native exit=$nativeExit`n$($o` field·값 또는 assignment를 다음 단계에 전달한다.
|
| 64줄F06-L64 | } |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 현재 object·array·block 또는 query 범위를 열거나 닫아 구조를 유지한다.
|
| 65줄F06-L65 | $line = |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | inner restore transcript의 exact success marker를 선택한다.
|
| 66줄F06-L66 | if ( |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 복구된 고정 fixture가 정확히 3행인지 기록하거나 검사한다.
|
| 67줄F06-L67 | throw "W22 transcript mismatch: |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | source와 restore 비교 불일치가 정확히 0인지 기록하거나 검사한다.
|
| 68줄F06-L68 | } |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 현재 object·array·block 또는 query 범위를 열거나 닫아 구조를 유지한다.
|
| 70줄F06-L70 | $innerPath = |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 정본 W22 disposable restore evidence producer에서 `$innerPath = Join-Path $evidence '5-restore-resu` field·값 또는 assignment를 다음 단계에 전달한다.
|
| 71줄F06-L71 | if ( |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 선행 invariant가 깨졌을 때 다음 단계로 진행하지 않도록 fail-closed guard를 적용한다.
|
| 72줄F06-L72 | throw 'W22 inner restore result missing' |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 정본 W22 disposable restore evidence producer의 72번째 원문을 앞 guard와 뒤 관찰값 사이에 연결한다.
|
| 73줄F06-L73 | } |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 현재 object·array·block 또는 query 범위를 열거나 닫아 구조를 유지한다.
|
| 74줄F06-L74 | $inner = |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 정본 W22 disposable restore evidence producer에서 `$inner = Get-Content -Raw -LiteralPath $innerPat` field·값 또는 assignment를 다음 단계에 전달한다.
|
| 75줄F06-L75 | if ( |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 복구된 고정 fixture가 정확히 3행인지 기록하거나 검사한다.
|
| 76줄F06-L76 | [ |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | source와 restore 비교 불일치가 정확히 0인지 기록하거나 검사한다.
|
| 77줄F06-L77 | throw 'W22 inner restore invariant mismatch' |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | source와 restore 비교 불일치가 정확히 0인지 기록하거나 검사한다.
|
| 78줄F06-L78 | } |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 현재 object·array·block 또는 query 범위를 열거나 닫아 구조를 유지한다.
|
| 79줄F06-L79 | $start = |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 정본 W22 disposable restore evidence producer에서 `$start = [DateTimeOffset]::MinValue` field·값 또는 assignment를 다음 단계에 전달한다.
|
| 80줄F06-L80 | $end = |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 정본 W22 disposable restore evidence producer에서 `$end = [DateTimeOffset]::MinValue` field·값 또는 assignment를 다음 단계에 전달한다.
|
| 81줄F06-L81 | if ( |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 선행 invariant가 깨졌을 때 다음 단계로 진행하지 않도록 fail-closed guard를 적용한다.
|
| 82줄F06-L82 | ![ |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 정본 W22 disposable restore evidence producer에서 `![DateTimeOffset]::TryParse([string]$inner.end_u` field·값 또는 assignment를 다음 단계에 전달한다.
|
| 83줄F06-L83 | throw 'W22 inner restore timestamps invalid' |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 정본 W22 disposable restore evidence producer의 83번째 원문을 앞 guard와 뒤 관찰값 사이에 연결한다.
|
| 84줄F06-L84 | } |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 현재 object·array·block 또는 query 범위를 열거나 닫아 구조를 유지한다.
|
| 86줄F06-L86 | $body = |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 정본 W22 disposable restore evidence producer에서 `$body = [ordered]@{` field·값 또는 assignment를 다음 단계에 전달한다.
|
| 87줄F06-L87 | owner = |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 정본 W22 disposable restore evidence producer에서 `owner = 'W22'` field·값 또는 assignment를 다음 단계에 전달한다.
|
| 88줄F06-L88 | run_id = |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 정본 W22 disposable restore evidence producer에서 `run_id = [guid]::NewGuid().ToString('N')` field·값 또는 assignment를 다음 단계에 전달한다.
|
| 89줄F06-L89 | started_at_utc = |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 정본 W22 disposable restore evidence producer에서 `started_at_utc = $start.ToString('o')` field·값 또는 assignment를 다음 단계에 전달한다.
|
| 90줄F06-L90 | completed_at_utc = |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 정본 W22 disposable restore evidence producer에서 `completed_at_utc = $end.ToString('o')` field·값 또는 assignment를 다음 단계에 전달한다.
|
| 91줄F06-L91 | source_db = |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 정본 W22 disposable restore evidence producer에서 `source_db = 'financial_core_restore_source'` field·값 또는 assignment를 다음 단계에 전달한다.
|
| 92줄F06-L92 | target_db = |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | disposable restore target 이름과 exact allowlist를 다룬다.
|
| 93줄F06-L93 | fixture_schema = |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 정본 W22 disposable restore evidence producer에서 `fixture_schema = 'restore_probe_v1'` field·값 또는 assignment를 다음 단계에 전달한다.
|
| 94줄F06-L94 | row_count = |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 복구된 고정 fixture가 정확히 3행인지 기록하거나 검사한다.
|
| 95줄F06-L95 | ledger_sum = |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 복구된 signed amount 합계가 정확히 120인지 기록하거나 검사한다.
|
| 96줄F06-L96 | mismatch = |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | source와 restore 비교 불일치가 정확히 0인지 기록하거나 검사한다.
|
| 97줄F06-L97 | rto_seconds = |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | disposable drill의 실측 restore 시간을 기록하되 production RTO로 확대하지 않는다.
|
| 98줄F06-L98 | dump_bytes = |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 정본 W22 disposable restore evidence producer에서 `dump_bytes = [long]$inner.dump_bytes` field·값 또는 assignment를 다음 단계에 전달한다.
|
| 99줄F06-L99 | source_dropped = |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 정본 W22 disposable restore evidence producer에서 `source_dropped = 1` field·값 또는 assignment를 다음 단계에 전달한다.
|
| 100줄F06-L100 | target_dropped = |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 정본 W22 disposable restore evidence producer에서 `target_dropped = 1` field·값 또는 assignment를 다음 단계에 전달한다.
|
| 101줄F06-L101 | cleanup = |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | source/target DB와 소유 resource 정리 결과를 evidence에 묶는다.
|
| 102줄F06-L102 | native_exit = |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 정본 W22 disposable restore evidence producer에서 `native_exit = 0` field·값 또는 assignment를 다음 단계에 전달한다.
|
| 103줄F06-L103 | inner_result_path = |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 정본 W22 disposable restore evidence producer에서 `inner_result_path = 'evidence/w22/5-restore-resu` field·값 또는 assignment를 다음 단계에 전달한다.
|
| 104줄F06-L104 | inner_result_sha256 = |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 현재 file bytes를 64-hex SHA-256 값과 결박하는 field 또는 검사를 다룬다.
|
| 105줄F06-L105 | } |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 현재 object·array·block 또는 query 범위를 열거나 닫아 구조를 유지한다.
|
| 106줄F06-L106 | } catch { |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 정본 W22 disposable restore evidence producer의 106번째 원문을 앞 guard와 뒤 관찰값 사이에 연결한다.
|
| 107줄F06-L107 | $failure = |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 정본 W22 disposable restore evidence producer에서 `$failure = $_` field·값 또는 assignment를 다음 단계에 전달한다.
|
| 108줄F06-L108 | } finally { |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 정본 W22 disposable restore evidence producer의 108번째 원문을 앞 guard와 뒤 관찰값 사이에 연결한다.
|
| 109줄F06-L109 | if ( |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 선행 invariant가 깨졌을 때 다음 단계로 진행하지 않도록 fail-closed guard를 적용한다.
|
| 110줄F06-L110 | & docker compose -f $compose -p $ComposeProject down -v --remove-orphans | Out-Null |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | W22가 소유한 DB Compose project를 시작하거나 finally에서 정리한다.
|
| 111줄F06-L111 | $composeCleanup = |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | source/target DB와 소유 resource 정리 결과를 evidence에 묶는다.
|
| 112줄F06-L112 | } else { |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 정본 W22 disposable restore evidence producer의 112번째 원문을 앞 guard와 뒤 관찰값 사이에 연결한다.
|
| 113줄F06-L113 | $composeCleanup = |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | source/target DB와 소유 resource 정리 결과를 evidence에 묶는다.
|
| 114줄F06-L114 | } |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 현재 object·array·block 또는 query 범위를 열거나 닫아 구조를 유지한다.
|
| 115줄F06-L115 | } |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 현재 object·array·block 또는 query 범위를 열거나 닫아 구조를 유지한다.
|
| 117줄F06-L117 | if ( |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | source/target DB와 소유 resource 정리 결과를 evidence에 묶는다.
|
| 118줄F06-L118 | if ( |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 선행 invariant가 깨졌을 때 다음 단계로 진행하지 않도록 fail-closed guard를 적용한다.
|
| 119줄F06-L119 | throw "W22 restore failed and owned Compose cleanup failed: |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | source/target DB와 소유 resource 정리 결과를 evidence에 묶는다.
|
| 120줄F06-L120 | } |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 현재 object·array·block 또는 query 범위를 열거나 닫아 구조를 유지한다.
|
| 121줄F06-L121 | throw 'W22 owned Compose cleanup failed' |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | source/target DB와 소유 resource 정리 결과를 evidence에 묶는다.
|
| 122줄F06-L122 | } |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 현재 object·array·block 또는 query 범위를 열거나 닫아 구조를 유지한다.
|
| 123줄F06-L123 | if ( |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 선행 invariant가 깨졌을 때 다음 단계로 진행하지 않도록 fail-closed guard를 적용한다.
|
| 124줄F06-L124 | if ( |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 선행 invariant가 깨졌을 때 다음 단계로 진행하지 않도록 fail-closed guard를 적용한다.
|
| 126줄F06-L126 | $body[ |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | source/target DB와 소유 resource 정리 결과를 evidence에 묶는다.
|
| 127줄F06-L127 | New-Item -ItemType Directory -Force $evidence | Out-Null |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 정본 W22 disposable restore evidence producer의 127번째 원문을 앞 guard와 뒤 관찰값 사이에 연결한다.
|
| 128줄F06-L128 | $resultPath = |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 정본 W22 disposable restore evidence producer에서 `$resultPath = Join-Path $evidence 'restore-resul` field·값 또는 assignment를 다음 단계에 전달한다.
|
| 129줄F06-L129 | $temporary = |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 정본 W22 disposable restore evidence producer에서 `$temporary = "$resultPath.tmp"` field·값 또는 assignment를 다음 단계에 전달한다.
|
| 130줄F06-L130 | $body | ConvertTo-Json -Depth 5 | Set-Content -Encoding utf8 -LiteralPath $temporary |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 정본 W22 disposable restore evidence producer의 130번째 원문을 앞 guard와 뒤 관찰값 사이에 연결한다.
|
| 131줄F06-L131 | Move-Item -LiteralPath $temporary -Destination $resultPath -Force |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 완성된 temporary evidence를 final path로 원자적으로 교체한다.
|
| 133줄F06-L133 | "W22_RESTORE_GREEN row_count= |
감독이 임시 원본 창고와 복구 창고를 만들고 3개 상자의 합계 120·불일치 0을 확인한 뒤 두 창고를 모두 철거하고 영수증을 원자적으로 교체하는 훈련 | 복구된 고정 fixture가 정확히 3행인지 기록하거나 검사한다.
|
Green 범위
-
marker나 파일이 보이면 전부 성공이야?
-
아니. source가 직접 검증한 범위만 말해야 해.
-
직접 연결되는 대표 값은 `W22_RESTORE_GREEN`이야.
-
`허용 target DB 이름만 쓴다`는 별도 증거가 필요해.
STEP 05 / 13
원본 코드 조각
원본을 12개 의미 조각으로 나누어 그대로 확인합니다.
파일을 한꺼번에 외우지 않고 실행 의미가 이어지는 작은 조각으로 봅니다. 아래 코드는 hash로 고정한 native 정본 source에서 그대로 잘랐습니다.
param(
[ValidateSet('Compose','Container')][string]$Mode = 'Compose',
[string]$ComposeProject = 'w22-restore-lab',
[string]$ContainerName = '',
[string]$EvidenceDir = 'evidence/w22',
[string]$TargetDb = 'financial_core_restore'
)
Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'
if ($TargetDb -cne 'financial_core_restore') {
throw 'W22 disposable target allowlist violation'
}
$root = Split-Path -Parent $PSScriptRoot
$evidence = if ([IO.Path]::IsPathRooted($EvidenceDir)) {
[IO.Path]::GetFullPath($EvidenceDir)
} else {
[IO.Path]::GetFullPath((Join-Path $root $EvidenceDir))
}
$tool = Join-Path $PSScriptRoot 'run-w42-restore-drill.ps1'
$compose = Join-Path $root 'compose.yaml'
$ownedCompose = $false
$composeCleanup = $false
$failure = $null
$body = $null
if (!(Test-Path -LiteralPath $tool -PathType Leaf)) {
throw 'W22 transitive W42 tool missing'
}
try {
if ($Mode -ceq 'Compose') {
if ($ContainerName) { throw 'W22 Compose mode rejects ContainerName' }
if ([string]::IsNullOrWhiteSpace($env:FCL_DB_PASSWORD)) {
$env:FCL_DB_PASSWORD = 'w22-disposable-password'
}
# Own the unique Compose project before startup so a partial `up`
# failure still reaches finally/down and cannot leak resources.
$ownedCompose = $true
& docker compose -f $compose -p $ComposeProject up -d --wait db
if ($LASTEXITCODE -ne 0) { throw "W22 compose up exit=$LASTEXITCODE" }
$ContainerName = (& docker compose -f $compose -p $ComposeProject ps -q db).Trim()
} elseif ([string]::IsNullOrWhiteSpace($ContainerName)) {
throw 'W22 Container mode requires ContainerName'
}
if ([string]::IsNullOrWhiteSpace($ContainerName)) {
throw 'W22 container resolution failed'
}
$output = @(
& powershell.exe -NoProfile -ExecutionPolicy Bypass -File $tool `
-Mode Container `
-ContainerName $ContainerName `
-AdminDatabase financial_core `
-Username app `
-TargetDb $TargetDb `
-EvidenceDir $evidence 2>&1
)
$nativeExit = $LASTEXITCODE
if ($nativeExit -ne 0) {
throw "W22 restore native exit=$nativeExit`n$($output -join "`n")"
}
$line = $output | Where-Object { $_ -match '^PASS W42_RESTORE ' } | Select-Object -Last 1
if (!$line -or $line -cnotmatch 'row_count=3 ledger_sum=120 mismatch=0 rto_seconds=([0-9]+(?:\.[0-9]+)?) source_dropped=1 target_dropped=1') {
throw "W22 transcript mismatch: $output"
}
$innerPath = Join-Path $evidence '5-restore-result.json'
if (!(Test-Path -LiteralPath $innerPath -PathType Leaf)) {
throw 'W22 inner restore result missing'
}
$inner = Get-Content -Raw -LiteralPath $innerPath | ConvertFrom-Json
if ([int]$inner.row_count -ne 3 -or [long]$inner.ledger_sum -ne 120 -or
[int]$inner.mismatch_count -ne 0 -or [long]$inner.dump_bytes -le 0) {
throw 'W22 inner restore invariant mismatch'
}
$start = [DateTimeOffset]::MinValue
$end = [DateTimeOffset]::MinValue
if (![DateTimeOffset]::TryParse([string]$inner.start_utc, [ref]$start) -or
![DateTimeOffset]::TryParse([string]$inner.end_utc, [ref]$end) -or $end -lt $start) {
throw 'W22 inner restore timestamps invalid'
}
$body = [ordered]@{
owner = 'W22'
run_id = [guid]::NewGuid().ToString('N')
started_at_utc = $start.ToString('o')
completed_at_utc = $end.ToString('o')
source_db = 'financial_core_restore_source'
target_db = $TargetDb
fixture_schema = 'restore_probe_v1'
row_count = 3
ledger_sum = 120
mismatch = 0
rto_seconds = [double]$inner.rto_seconds
dump_bytes = [long]$inner.dump_bytes
source_dropped = 1
target_dropped = 1
cleanup = 1
native_exit = 0
inner_result_path = 'evidence/w22/5-restore-result.json'
inner_result_sha256 = (Get-FileHash -LiteralPath $innerPath -Algorithm SHA256).Hash.ToLowerInvariant()
}
} catch {
$failure = $_
} finally {
if ($ownedCompose) {
& docker compose -f $compose -p $ComposeProject down -v --remove-orphans | Out-Null
$composeCleanup = ($LASTEXITCODE -eq 0)
} else {
$composeCleanup = $true
}
}
if (!$composeCleanup) {
if ($null -ne $failure) {
throw "W22 restore failed and owned Compose cleanup failed: $($failure.Exception.Message)"
}
throw 'W22 owned Compose cleanup failed'
}
if ($null -ne $failure) { throw $failure }
if ($null -eq $body) { throw 'W22 restore produced no canonical result' }
$body['compose_cleanup'] = if ($ownedCompose) { 1 } else { 'not-owned' }
New-Item -ItemType Directory -Force $evidence | Out-Null
$resultPath = Join-Path $evidence 'restore-result.json'
$temporary = "$resultPath.tmp"
$body | ConvertTo-Json -Depth 5 | Set-Content -Encoding utf8 -LiteralPath $temporary
Move-Item -LiteralPath $temporary -Destination $resultPath -Force
"W22_RESTORE_GREEN row_count=3 ledger_sum=120 mismatch=0 rto_seconds=$($body.rto_seconds) cleanup=1 native_exit=0"
STEP 06 / 13
코드 한 줄씩 한국어로 번역
비어 있지 않은 122줄을 모두 한국어로 옮깁니다.
비어 있지 않은 원본 줄은 하나도 생략하지 않습니다.
| 줄 | 원본 | 한국어 번역 |
|---|---|---|
| 1 | param( | W22 restore runner의 호출 parameter 계약을 연다. |
| 2 | [ValidateSet('Compose','Container')][string]$Mode = 'Compose', | 허용 실행 mode를 Compose와 Container 두 값으로 제한한다. |
| 3 | [string]$ComposeProject = 'w22-restore-lab', | 정본 W22 disposable restore evidence producer에서 `[string]$ComposeProject = 'w22-restore-lab',` field·값 또는 assignment를 다음 단계에 전달한다. |
| 4 | [string]$ContainerName = '', | 정본 W22 disposable restore evidence producer에서 `[string]$ContainerName = '',` field·값 또는 assignment를 다음 단계에 전달한다. |
| 5 | [string]$EvidenceDir = 'evidence/w22', | 정본 W22 disposable restore evidence producer에서 `[string]$EvidenceDir = 'evidence/w22',` field·값 또는 assignment를 다음 단계에 전달한다. |
| 6 | [string]$TargetDb = 'financial_core_restore' | disposable restore target 이름과 exact allowlist를 다룬다. |
| 7 | ) | 현재 object·array·block 또는 query 범위를 열거나 닫아 구조를 유지한다. |
| 9 | Set-StrictMode -Version Latest | 미정의 변수 등 PowerShell 오류를 조기에 드러낸다. |
| 10 | $ErrorActionPreference = 'Stop' | PowerShell cmdlet 오류를 terminating error로 처리한다. |
| 12 | if ($TargetDb -cne 'financial_core_restore') { | disposable restore target 이름과 exact allowlist를 다룬다. |
| 13 | throw 'W22 disposable target allowlist violation' | 정본 W22 disposable restore evidence producer의 13번째 원문을 앞 guard와 뒤 관찰값 사이에 연결한다. |
| 14 | } | 현재 object·array·block 또는 query 범위를 열거나 닫아 구조를 유지한다. |
| 16 | $root = Split-Path -Parent $PSScriptRoot | 정본 W22 disposable restore evidence producer에서 `$root = Split-Path -Parent $PSScriptRoot` field·값 또는 assignment를 다음 단계에 전달한다. |
| 17 | $evidence = if ([IO.Path]::IsPathRooted($EvidenceDir)) { | 정본 W22 disposable restore evidence producer에서 `$evidence = if ([IO.Path]::IsPathRooted($Evidenc` field·값 또는 assignment를 다음 단계에 전달한다. |
| 18 | [IO.Path]::GetFullPath($EvidenceDir) | 정본 W22 disposable restore evidence producer에서 `[IO.Path]::GetFullPath($EvidenceDir)` field·값 또는 assignment를 다음 단계에 전달한다. |
| 19 | } else { | 정본 W22 disposable restore evidence producer의 19번째 원문을 앞 guard와 뒤 관찰값 사이에 연결한다. |
| 20 | [IO.Path]::GetFullPath((Join-Path $root $EvidenceDir)) | 정본 W22 disposable restore evidence producer에서 `[IO.Path]::GetFullPath((Join-Path $root $Evidenc` field·값 또는 assignment를 다음 단계에 전달한다. |
| 21 | } | 현재 object·array·block 또는 query 범위를 열거나 닫아 구조를 유지한다. |
| 22 | $tool = Join-Path $PSScriptRoot 'run-w42-restore-drill.ps1' | 완전한 restore 수행을 맡는 packaged W42 transitive tool을 찾는다. |
| 23 | $compose = Join-Path $root 'compose.yaml' | 정본 W22 disposable restore evidence producer에서 `$compose = Join-Path $root 'compose.yaml'` field·값 또는 assignment를 다음 단계에 전달한다. |
| 24 | $ownedCompose = $false | 정본 W22 disposable restore evidence producer에서 `$ownedCompose = $false` field·값 또는 assignment를 다음 단계에 전달한다. |
| 25 | $composeCleanup = $false | source/target DB와 소유 resource 정리 결과를 evidence에 묶는다. |
| 26 | $failure = $null | 정본 W22 disposable restore evidence producer에서 `$failure = $null` field·값 또는 assignment를 다음 단계에 전달한다. |
| 27 | $body = $null | 정본 W22 disposable restore evidence producer에서 `$body = $null` field·값 또는 assignment를 다음 단계에 전달한다. |
| 29 | if (!(Test-Path -LiteralPath $tool -PathType Leaf)) { | 선행 invariant가 깨졌을 때 다음 단계로 진행하지 않도록 fail-closed guard를 적용한다. |
| 30 | throw 'W22 transitive W42 tool missing' | 정본 W22 disposable restore evidence producer의 30번째 원문을 앞 guard와 뒤 관찰값 사이에 연결한다. |
| 31 | } | 현재 object·array·block 또는 query 범위를 열거나 닫아 구조를 유지한다. |
| 33 | try { | 정본 W22 disposable restore evidence producer의 33번째 원문을 앞 guard와 뒤 관찰값 사이에 연결한다. |
| 34 | if ($Mode -ceq 'Compose') { | 선행 invariant가 깨졌을 때 다음 단계로 진행하지 않도록 fail-closed guard를 적용한다. |
| 35 | if ($ContainerName) { throw 'W22 Compose mode rejects ContainerName' } | 선행 invariant가 깨졌을 때 다음 단계로 진행하지 않도록 fail-closed guard를 적용한다. |
| 36 | if ([string]::IsNullOrWhiteSpace($env:FCL_DB_PASSWORD)) { | 선행 invariant가 깨졌을 때 다음 단계로 진행하지 않도록 fail-closed guard를 적용한다. |
| 37 | $env:FCL_DB_PASSWORD = 'w22-disposable-password' | 정본 W22 disposable restore evidence producer에서 `$env:FCL_DB_PASSWORD = 'w22-disposable-password'` field·값 또는 assignment를 다음 단계에 전달한다. |
| 38 | } | 현재 object·array·block 또는 query 범위를 열거나 닫아 구조를 유지한다. |
| 39 | # Own the unique Compose project before startup so a partial `up` | 이 source의 비정본 provenance, 가정, 반례, 또는 실행 경계를 사람이 확인할 주석이다. |
| 40 | # failure still reaches finally/down and cannot leak resources. | 이 source의 비정본 provenance, 가정, 반례, 또는 실행 경계를 사람이 확인할 주석이다. |
| 41 | $ownedCompose = $true | 정본 W22 disposable restore evidence producer에서 `$ownedCompose = $true` field·값 또는 assignment를 다음 단계에 전달한다. |
| 42 | & docker compose -f $compose -p $ComposeProject up -d --wait db | W22가 소유한 DB Compose project를 시작하거나 finally에서 정리한다. |
| 43 | if ($LASTEXITCODE -ne 0) { throw "W22 compose up exit=$LASTEXITCODE" } | 선행 invariant가 깨졌을 때 다음 단계로 진행하지 않도록 fail-closed guard를 적용한다. |
| 44 | $ContainerName = (& docker compose -f $compose -p $ComposeProject ps -q db).Trim() | W22가 소유한 DB Compose project를 시작하거나 finally에서 정리한다. |
| 45 | } elseif ([string]::IsNullOrWhiteSpace($ContainerName)) { | 정본 W22 disposable restore evidence producer에서 `} elseif ([string]::IsNullOrWhiteSpace($Containe` field·값 또는 assignment를 다음 단계에 전달한다. |
| 46 | throw 'W22 Container mode requires ContainerName' | 정본 W22 disposable restore evidence producer의 46번째 원문을 앞 guard와 뒤 관찰값 사이에 연결한다. |
| 47 | } | 현재 object·array·block 또는 query 범위를 열거나 닫아 구조를 유지한다. |
| 48 | if ([string]::IsNullOrWhiteSpace($ContainerName)) { | 선행 invariant가 깨졌을 때 다음 단계로 진행하지 않도록 fail-closed guard를 적용한다. |
| 49 | throw 'W22 container resolution failed' | 정본 W22 disposable restore evidence producer의 49번째 원문을 앞 guard와 뒤 관찰값 사이에 연결한다. |
| 50 | } | 현재 object·array·block 또는 query 범위를 열거나 닫아 구조를 유지한다. |
| 52 | $output = @( | 정본 W22 disposable restore evidence producer에서 `$output = @(` field·값 또는 assignment를 다음 단계에 전달한다. |
| 53 | & powershell.exe -NoProfile -ExecutionPolicy Bypass -File $tool ` | 정본 W22 disposable restore evidence producer의 53번째 원문을 앞 guard와 뒤 관찰값 사이에 연결한다. |
| 54 | -Mode Container ` | 정본 W22 disposable restore evidence producer의 54번째 원문을 앞 guard와 뒤 관찰값 사이에 연결한다. |
| 55 | -ContainerName $ContainerName ` | 정본 W22 disposable restore evidence producer의 55번째 원문을 앞 guard와 뒤 관찰값 사이에 연결한다. |
| 56 | -AdminDatabase financial_core ` | 정본 W22 disposable restore evidence producer의 56번째 원문을 앞 guard와 뒤 관찰값 사이에 연결한다. |
| 57 | -Username app ` | 정본 W22 disposable restore evidence producer의 57번째 원문을 앞 guard와 뒤 관찰값 사이에 연결한다. |
| 58 | -TargetDb $TargetDb ` | disposable restore target 이름과 exact allowlist를 다룬다. |
| 59 | -EvidenceDir $evidence 2>&1 | 정본 W22 disposable restore evidence producer의 59번째 원문을 앞 guard와 뒤 관찰값 사이에 연결한다. |
| 60 | ) | 현재 object·array·block 또는 query 범위를 열거나 닫아 구조를 유지한다. |
| 61 | $nativeExit = $LASTEXITCODE | 정본 W22 disposable restore evidence producer에서 `$nativeExit = $LASTEXITCODE` field·값 또는 assignment를 다음 단계에 전달한다. |
| 62 | if ($nativeExit -ne 0) { | 선행 invariant가 깨졌을 때 다음 단계로 진행하지 않도록 fail-closed guard를 적용한다. |
| 63 | throw "W22 restore native exit=$nativeExit`n$($output -join "`n")" | 정본 W22 disposable restore evidence producer에서 `throw "W22 restore native exit=$nativeExit`n$($o` field·값 또는 assignment를 다음 단계에 전달한다. |
| 64 | } | 현재 object·array·block 또는 query 범위를 열거나 닫아 구조를 유지한다. |
| 65 | $line = $output | Where-Object { $_ -match '^PASS W42_RESTORE ' } | Select-Object -Last 1 | inner restore transcript의 exact success marker를 선택한다. |
| 66 | if (!$line -or $line -cnotmatch 'row_count=3 ledger_sum=120 mismatch=0 rto_seconds=([0-9]+(?:\.[0-9]+)?) source_dropped=1 target_dropped=1') { | 복구된 고정 fixture가 정확히 3행인지 기록하거나 검사한다. |
| 67 | throw "W22 transcript mismatch: $output" | source와 restore 비교 불일치가 정확히 0인지 기록하거나 검사한다. |
| 68 | } | 현재 object·array·block 또는 query 범위를 열거나 닫아 구조를 유지한다. |
| 70 | $innerPath = Join-Path $evidence '5-restore-result.json' | 정본 W22 disposable restore evidence producer에서 `$innerPath = Join-Path $evidence '5-restore-resu` field·값 또는 assignment를 다음 단계에 전달한다. |
| 71 | if (!(Test-Path -LiteralPath $innerPath -PathType Leaf)) { | 선행 invariant가 깨졌을 때 다음 단계로 진행하지 않도록 fail-closed guard를 적용한다. |
| 72 | throw 'W22 inner restore result missing' | 정본 W22 disposable restore evidence producer의 72번째 원문을 앞 guard와 뒤 관찰값 사이에 연결한다. |
| 73 | } | 현재 object·array·block 또는 query 범위를 열거나 닫아 구조를 유지한다. |
| 74 | $inner = Get-Content -Raw -LiteralPath $innerPath | ConvertFrom-Json | 정본 W22 disposable restore evidence producer에서 `$inner = Get-Content -Raw -LiteralPath $innerPat` field·값 또는 assignment를 다음 단계에 전달한다. |
| 75 | if ([int]$inner.row_count -ne 3 -or [long]$inner.ledger_sum -ne 120 -or | 복구된 고정 fixture가 정확히 3행인지 기록하거나 검사한다. |
| 76 | [int]$inner.mismatch_count -ne 0 -or [long]$inner.dump_bytes -le 0) { | source와 restore 비교 불일치가 정확히 0인지 기록하거나 검사한다. |
| 77 | throw 'W22 inner restore invariant mismatch' | source와 restore 비교 불일치가 정확히 0인지 기록하거나 검사한다. |
| 78 | } | 현재 object·array·block 또는 query 범위를 열거나 닫아 구조를 유지한다. |
| 79 | $start = [DateTimeOffset]::MinValue | 정본 W22 disposable restore evidence producer에서 `$start = [DateTimeOffset]::MinValue` field·값 또는 assignment를 다음 단계에 전달한다. |
| 80 | $end = [DateTimeOffset]::MinValue | 정본 W22 disposable restore evidence producer에서 `$end = [DateTimeOffset]::MinValue` field·값 또는 assignment를 다음 단계에 전달한다. |
| 81 | if (![DateTimeOffset]::TryParse([string]$inner.start_utc, [ref]$start) -or | 선행 invariant가 깨졌을 때 다음 단계로 진행하지 않도록 fail-closed guard를 적용한다. |
| 82 | ![DateTimeOffset]::TryParse([string]$inner.end_utc, [ref]$end) -or $end -lt $start) { | 정본 W22 disposable restore evidence producer에서 `![DateTimeOffset]::TryParse([string]$inner.end_u` field·값 또는 assignment를 다음 단계에 전달한다. |
| 83 | throw 'W22 inner restore timestamps invalid' | 정본 W22 disposable restore evidence producer의 83번째 원문을 앞 guard와 뒤 관찰값 사이에 연결한다. |
| 84 | } | 현재 object·array·block 또는 query 범위를 열거나 닫아 구조를 유지한다. |
| 86 | $body = [ordered]@{ | 정본 W22 disposable restore evidence producer에서 `$body = [ordered]@{` field·값 또는 assignment를 다음 단계에 전달한다. |
| 87 | owner = 'W22' | 정본 W22 disposable restore evidence producer에서 `owner = 'W22'` field·값 또는 assignment를 다음 단계에 전달한다. |
| 88 | run_id = [guid]::NewGuid().ToString('N') | 정본 W22 disposable restore evidence producer에서 `run_id = [guid]::NewGuid().ToString('N')` field·값 또는 assignment를 다음 단계에 전달한다. |
| 89 | started_at_utc = $start.ToString('o') | 정본 W22 disposable restore evidence producer에서 `started_at_utc = $start.ToString('o')` field·값 또는 assignment를 다음 단계에 전달한다. |
| 90 | completed_at_utc = $end.ToString('o') | 정본 W22 disposable restore evidence producer에서 `completed_at_utc = $end.ToString('o')` field·값 또는 assignment를 다음 단계에 전달한다. |
| 91 | source_db = 'financial_core_restore_source' | 정본 W22 disposable restore evidence producer에서 `source_db = 'financial_core_restore_source'` field·값 또는 assignment를 다음 단계에 전달한다. |
| 92 | target_db = $TargetDb | disposable restore target 이름과 exact allowlist를 다룬다. |
| 93 | fixture_schema = 'restore_probe_v1' | 정본 W22 disposable restore evidence producer에서 `fixture_schema = 'restore_probe_v1'` field·값 또는 assignment를 다음 단계에 전달한다. |
| 94 | row_count = 3 | 복구된 고정 fixture가 정확히 3행인지 기록하거나 검사한다. |
| 95 | ledger_sum = 120 | 복구된 signed amount 합계가 정확히 120인지 기록하거나 검사한다. |
| 96 | mismatch = 0 | source와 restore 비교 불일치가 정확히 0인지 기록하거나 검사한다. |
| 97 | rto_seconds = [double]$inner.rto_seconds | disposable drill의 실측 restore 시간을 기록하되 production RTO로 확대하지 않는다. |
| 98 | dump_bytes = [long]$inner.dump_bytes | 정본 W22 disposable restore evidence producer에서 `dump_bytes = [long]$inner.dump_bytes` field·값 또는 assignment를 다음 단계에 전달한다. |
| 99 | source_dropped = 1 | 정본 W22 disposable restore evidence producer에서 `source_dropped = 1` field·값 또는 assignment를 다음 단계에 전달한다. |
| 100 | target_dropped = 1 | 정본 W22 disposable restore evidence producer에서 `target_dropped = 1` field·값 또는 assignment를 다음 단계에 전달한다. |
| 101 | cleanup = 1 | source/target DB와 소유 resource 정리 결과를 evidence에 묶는다. |
| 102 | native_exit = 0 | 정본 W22 disposable restore evidence producer에서 `native_exit = 0` field·값 또는 assignment를 다음 단계에 전달한다. |
| 103 | inner_result_path = 'evidence/w22/5-restore-result.json' | 정본 W22 disposable restore evidence producer에서 `inner_result_path = 'evidence/w22/5-restore-resu` field·값 또는 assignment를 다음 단계에 전달한다. |
| 104 | inner_result_sha256 = (Get-FileHash -LiteralPath $innerPath -Algorithm SHA256).Hash.ToLowerInvariant() | 현재 file bytes를 64-hex SHA-256 값과 결박하는 field 또는 검사를 다룬다. |
| 105 | } | 현재 object·array·block 또는 query 범위를 열거나 닫아 구조를 유지한다. |
| 106 | } catch { | 정본 W22 disposable restore evidence producer의 106번째 원문을 앞 guard와 뒤 관찰값 사이에 연결한다. |
| 107 | $failure = $_ | 정본 W22 disposable restore evidence producer에서 `$failure = $_` field·값 또는 assignment를 다음 단계에 전달한다. |
| 108 | } finally { | 정본 W22 disposable restore evidence producer의 108번째 원문을 앞 guard와 뒤 관찰값 사이에 연결한다. |
| 109 | if ($ownedCompose) { | 선행 invariant가 깨졌을 때 다음 단계로 진행하지 않도록 fail-closed guard를 적용한다. |
| 110 | & docker compose -f $compose -p $ComposeProject down -v --remove-orphans | Out-Null | W22가 소유한 DB Compose project를 시작하거나 finally에서 정리한다. |
| 111 | $composeCleanup = ($LASTEXITCODE -eq 0) | source/target DB와 소유 resource 정리 결과를 evidence에 묶는다. |
| 112 | } else { | 정본 W22 disposable restore evidence producer의 112번째 원문을 앞 guard와 뒤 관찰값 사이에 연결한다. |
| 113 | $composeCleanup = $true | source/target DB와 소유 resource 정리 결과를 evidence에 묶는다. |
| 114 | } | 현재 object·array·block 또는 query 범위를 열거나 닫아 구조를 유지한다. |
| 115 | } | 현재 object·array·block 또는 query 범위를 열거나 닫아 구조를 유지한다. |
| 117 | if (!$composeCleanup) { | source/target DB와 소유 resource 정리 결과를 evidence에 묶는다. |
| 118 | if ($null -ne $failure) { | 선행 invariant가 깨졌을 때 다음 단계로 진행하지 않도록 fail-closed guard를 적용한다. |
| 119 | throw "W22 restore failed and owned Compose cleanup failed: $($failure.Exception.Message)" | source/target DB와 소유 resource 정리 결과를 evidence에 묶는다. |
| 120 | } | 현재 object·array·block 또는 query 범위를 열거나 닫아 구조를 유지한다. |
| 121 | throw 'W22 owned Compose cleanup failed' | source/target DB와 소유 resource 정리 결과를 evidence에 묶는다. |
| 122 | } | 현재 object·array·block 또는 query 범위를 열거나 닫아 구조를 유지한다. |
| 123 | if ($null -ne $failure) { throw $failure } | 선행 invariant가 깨졌을 때 다음 단계로 진행하지 않도록 fail-closed guard를 적용한다. |
| 124 | if ($null -eq $body) { throw 'W22 restore produced no canonical result' } | 선행 invariant가 깨졌을 때 다음 단계로 진행하지 않도록 fail-closed guard를 적용한다. |
| 126 | $body['compose_cleanup'] = if ($ownedCompose) { 1 } else { 'not-owned' } | source/target DB와 소유 resource 정리 결과를 evidence에 묶는다. |
| 127 | New-Item -ItemType Directory -Force $evidence | Out-Null | 정본 W22 disposable restore evidence producer의 127번째 원문을 앞 guard와 뒤 관찰값 사이에 연결한다. |
| 128 | $resultPath = Join-Path $evidence 'restore-result.json' | 정본 W22 disposable restore evidence producer에서 `$resultPath = Join-Path $evidence 'restore-resul` field·값 또는 assignment를 다음 단계에 전달한다. |
| 129 | $temporary = "$resultPath.tmp" | 정본 W22 disposable restore evidence producer에서 `$temporary = "$resultPath.tmp"` field·값 또는 assignment를 다음 단계에 전달한다. |
| 130 | $body | ConvertTo-Json -Depth 5 | Set-Content -Encoding utf8 -LiteralPath $temporary | 정본 W22 disposable restore evidence producer의 130번째 원문을 앞 guard와 뒤 관찰값 사이에 연결한다. |
| 131 | Move-Item -LiteralPath $temporary -Destination $resultPath -Force | 완성된 temporary evidence를 final path로 원자적으로 교체한다. |
| 133 | "W22_RESTORE_GREEN row_count=3 ledger_sum=120 mismatch=0 rto_seconds=$($body.rto_seconds) cleanup=1 native_exit=0" | 복구된 고정 fixture가 정확히 3행인지 기록하거나 검사한다. |
STEP 07 / 13
기존 수준의 한 줄 읽기·문법 해부
쉬운 설명 다음에 문법과 실행 순서를 정밀하게 읽습니다.
한 줄로 읽기고정 3행을 별도 DB에 dump/restore해 3·120·0과 cleanup을 검증하고 canonical restore-result.json을 atomic publish하는 W22 packaged owner다. 다만 production RPO/RTO 보장이 아니다
문법 해부
- `try/catch/finally`는 실패 여부와 무관하게 소유한 Compose cleanup을 수행한다.
- native command 뒤 `$LASTEXITCODE`와 transcript regex·inner JSON을 함께 검증한다.
실행 순서
- allowlist와 transitive tool을 검사한다.
- Compose 또는 caller container를 선택한다.
- W42 restore 결과 3·120·0을 재검증한다.
- cleanup 뒤 restore-result.json을 atomic publish한다.
W22 조각별 정밀 해설
F06-C01 · 원문 1–12줄
- 문법 해부
- 1~12줄의 `원문 1–12줄`을 입력·guard·관찰·cleanup 단계로 나눈다.
- 실제 값 추적
- 항목 전체 흐름에 연결해 `row_count=3`을 대조한다. 이 값이 chunk 단독 산출이라는 뜻은 아니다.
- 정상 예
- 정상 예에서는 source 순서와 owner 계약이 일치해 `row_count=3`을 관찰한다.
- 틀린 예·반례
- 반례에서는 선행 guard·stable order·cleanup을 생략한다. 동결 경계: production RPO/RTO 보장이 아니다.
- 착각 방지
- `원문 1–12줄`이 항목 전체 Green을 단독 증명한다고 읽지 않는다.
- 하지 않는 일
- 이 chunk가 책임지지 않는 범위: production RPO/RTO 보장이 아니다.
- 다음 연결
- 다음 source chunk의 입력 또는 최종 marker/SQL oracle로 결과를 넘긴다.
F06-C02 · 원문 13–24줄
- 문법 해부
- 13~24줄의 `원문 13–24줄`을 입력·guard·관찰·cleanup 단계로 나눈다.
- 실제 값 추적
- 항목 전체 흐름에 연결해 `ledger_sum=120`을 대조한다. 이 값이 chunk 단독 산출이라는 뜻은 아니다.
- 정상 예
- 정상 예에서는 source 순서와 owner 계약이 일치해 `ledger_sum=120`을 관찰한다.
- 틀린 예·반례
- 반례에서는 선행 guard·stable order·cleanup을 생략한다. 동결 경계: run-w42-restore-drill.ps1에 transitive 의존한다.
- 착각 방지
- `원문 13–24줄`이 항목 전체 Green을 단독 증명한다고 읽지 않는다.
- 하지 않는 일
- 이 chunk가 책임지지 않는 범위: run-w42-restore-drill.ps1에 transitive 의존한다.
- 다음 연결
- 다음 source chunk의 입력 또는 최종 marker/SQL oracle로 결과를 넘긴다.
F06-C03 · 원문 25–36줄
- 문법 해부
- 25~36줄의 `원문 25–36줄`을 입력·guard·관찰·cleanup 단계로 나눈다.
- 실제 값 추적
- 항목 전체 흐름에 연결해 `mismatch=0`을 대조한다. 이 값이 chunk 단독 산출이라는 뜻은 아니다.
- 정상 예
- 정상 예에서는 source 순서와 owner 계약이 일치해 `mismatch=0`을 관찰한다.
- 틀린 예·반례
- 반례에서는 선행 guard·stable order·cleanup을 생략한다. 동결 경계: 허용 target DB 이름만 쓴다.
- 착각 방지
- `원문 25–36줄`이 항목 전체 Green을 단독 증명한다고 읽지 않는다.
- 하지 않는 일
- 이 chunk가 책임지지 않는 범위: 허용 target DB 이름만 쓴다.
- 다음 연결
- 다음 source chunk의 입력 또는 최종 marker/SQL oracle로 결과를 넘긴다.
F06-C04 · 원문 37–48줄
- 문법 해부
- 37~48줄의 `원문 37–48줄`을 입력·guard·관찰·cleanup 단계로 나눈다.
- 실제 값 추적
- 항목 전체 흐름에 연결해 `cleanup=1`을 대조한다. 이 값이 chunk 단독 산출이라는 뜻은 아니다.
- 정상 예
- 정상 예에서는 source 순서와 owner 계약이 일치해 `cleanup=1`을 관찰한다.
- 틀린 예·반례
- 반례에서는 선행 guard·stable order·cleanup을 생략한다. 동결 경계: Docker·PostgreSQL 실행 환경이 필요하다.
- 착각 방지
- `원문 37–48줄`이 항목 전체 Green을 단독 증명한다고 읽지 않는다.
- 하지 않는 일
- 이 chunk가 책임지지 않는 범위: Docker·PostgreSQL 실행 환경이 필요하다.
- 다음 연결
- 다음 source chunk의 입력 또는 최종 marker/SQL oracle로 결과를 넘긴다.
F06-C05 · 원문 49–60줄
- 문법 해부
- 49~60줄의 `원문 49–60줄`을 입력·guard·관찰·cleanup 단계로 나눈다.
- 실제 값 추적
- 항목 전체 흐름에 연결해 `W22_RESTORE_GREEN`을 대조한다. 이 값이 chunk 단독 산출이라는 뜻은 아니다.
- 정상 예
- 정상 예에서는 source 순서와 owner 계약이 일치해 `W22_RESTORE_GREEN`을 관찰한다.
- 틀린 예·반례
- 반례에서는 선행 guard·stable order·cleanup을 생략한다. 동결 경계: production RPO/RTO 보장이 아니다.
- 착각 방지
- `원문 49–60줄`이 항목 전체 Green을 단독 증명한다고 읽지 않는다.
- 하지 않는 일
- 이 chunk가 책임지지 않는 범위: production RPO/RTO 보장이 아니다.
- 다음 연결
- 다음 source chunk의 입력 또는 최종 marker/SQL oracle로 결과를 넘긴다.
F06-C06 · 원문 61–72줄
- 문법 해부
- 61~72줄의 `원문 61–72줄`을 입력·guard·관찰·cleanup 단계로 나눈다.
- 실제 값 추적
- 항목 전체 흐름에 연결해 `row_count=3`을 대조한다. 이 값이 chunk 단독 산출이라는 뜻은 아니다.
- 정상 예
- 정상 예에서는 source 순서와 owner 계약이 일치해 `row_count=3`을 관찰한다.
- 틀린 예·반례
- 반례에서는 선행 guard·stable order·cleanup을 생략한다. 동결 경계: run-w42-restore-drill.ps1에 transitive 의존한다.
- 착각 방지
- `원문 61–72줄`이 항목 전체 Green을 단독 증명한다고 읽지 않는다.
- 하지 않는 일
- 이 chunk가 책임지지 않는 범위: run-w42-restore-drill.ps1에 transitive 의존한다.
- 다음 연결
- 다음 source chunk의 입력 또는 최종 marker/SQL oracle로 결과를 넘긴다.
F06-C07 · 원문 73–84줄
- 문법 해부
- 73~84줄의 `원문 73–84줄`을 입력·guard·관찰·cleanup 단계로 나눈다.
- 실제 값 추적
- 항목 전체 흐름에 연결해 `ledger_sum=120`을 대조한다. 이 값이 chunk 단독 산출이라는 뜻은 아니다.
- 정상 예
- 정상 예에서는 source 순서와 owner 계약이 일치해 `ledger_sum=120`을 관찰한다.
- 틀린 예·반례
- 반례에서는 선행 guard·stable order·cleanup을 생략한다. 동결 경계: 허용 target DB 이름만 쓴다.
- 착각 방지
- `원문 73–84줄`이 항목 전체 Green을 단독 증명한다고 읽지 않는다.
- 하지 않는 일
- 이 chunk가 책임지지 않는 범위: 허용 target DB 이름만 쓴다.
- 다음 연결
- 다음 source chunk의 입력 또는 최종 marker/SQL oracle로 결과를 넘긴다.
F06-C08 · 원문 85–96줄
- 문법 해부
- 85~96줄의 `원문 85–96줄`을 입력·guard·관찰·cleanup 단계로 나눈다.
- 실제 값 추적
- 항목 전체 흐름에 연결해 `mismatch=0`을 대조한다. 이 값이 chunk 단독 산출이라는 뜻은 아니다.
- 정상 예
- 정상 예에서는 source 순서와 owner 계약이 일치해 `mismatch=0`을 관찰한다.
- 틀린 예·반례
- 반례에서는 선행 guard·stable order·cleanup을 생략한다. 동결 경계: Docker·PostgreSQL 실행 환경이 필요하다.
- 착각 방지
- `원문 85–96줄`이 항목 전체 Green을 단독 증명한다고 읽지 않는다.
- 하지 않는 일
- 이 chunk가 책임지지 않는 범위: Docker·PostgreSQL 실행 환경이 필요하다.
- 다음 연결
- 다음 source chunk의 입력 또는 최종 marker/SQL oracle로 결과를 넘긴다.
F06-C09 · 원문 97–108줄
- 문법 해부
- 97~108줄의 `원문 97–108줄`을 입력·guard·관찰·cleanup 단계로 나눈다.
- 실제 값 추적
- 항목 전체 흐름에 연결해 `cleanup=1`을 대조한다. 이 값이 chunk 단독 산출이라는 뜻은 아니다.
- 정상 예
- 정상 예에서는 source 순서와 owner 계약이 일치해 `cleanup=1`을 관찰한다.
- 틀린 예·반례
- 반례에서는 선행 guard·stable order·cleanup을 생략한다. 동결 경계: production RPO/RTO 보장이 아니다.
- 착각 방지
- `원문 97–108줄`이 항목 전체 Green을 단독 증명한다고 읽지 않는다.
- 하지 않는 일
- 이 chunk가 책임지지 않는 범위: production RPO/RTO 보장이 아니다.
- 다음 연결
- 다음 source chunk의 입력 또는 최종 marker/SQL oracle로 결과를 넘긴다.
F06-C10 · 원문 109–120줄
- 문법 해부
- 109~120줄의 `원문 109–120줄`을 입력·guard·관찰·cleanup 단계로 나눈다.
- 실제 값 추적
- 항목 전체 흐름에 연결해 `W22_RESTORE_GREEN`을 대조한다. 이 값이 chunk 단독 산출이라는 뜻은 아니다.
- 정상 예
- 정상 예에서는 source 순서와 owner 계약이 일치해 `W22_RESTORE_GREEN`을 관찰한다.
- 틀린 예·반례
- 반례에서는 선행 guard·stable order·cleanup을 생략한다. 동결 경계: run-w42-restore-drill.ps1에 transitive 의존한다.
- 착각 방지
- `원문 109–120줄`이 항목 전체 Green을 단독 증명한다고 읽지 않는다.
- 하지 않는 일
- 이 chunk가 책임지지 않는 범위: run-w42-restore-drill.ps1에 transitive 의존한다.
- 다음 연결
- 다음 source chunk의 입력 또는 최종 marker/SQL oracle로 결과를 넘긴다.
F06-C11 · 원문 121–132줄
- 문법 해부
- 121~132줄의 `원문 121–132줄`을 입력·guard·관찰·cleanup 단계로 나눈다.
- 실제 값 추적
- 항목 전체 흐름에 연결해 `row_count=3`을 대조한다. 이 값이 chunk 단독 산출이라는 뜻은 아니다.
- 정상 예
- 정상 예에서는 source 순서와 owner 계약이 일치해 `row_count=3`을 관찰한다.
- 틀린 예·반례
- 반례에서는 선행 guard·stable order·cleanup을 생략한다. 동결 경계: 허용 target DB 이름만 쓴다.
- 착각 방지
- `원문 121–132줄`이 항목 전체 Green을 단독 증명한다고 읽지 않는다.
- 하지 않는 일
- 이 chunk가 책임지지 않는 범위: 허용 target DB 이름만 쓴다.
- 다음 연결
- 다음 source chunk의 입력 또는 최종 marker/SQL oracle로 결과를 넘긴다.
F06-C12 · 원문 133–133줄
- 문법 해부
- 133~133줄의 `원문 133–133줄`을 입력·guard·관찰·cleanup 단계로 나눈다.
- 실제 값 추적
- 항목 전체 흐름에 연결해 `ledger_sum=120`을 대조한다. 이 값이 chunk 단독 산출이라는 뜻은 아니다.
- 정상 예
- 정상 예에서는 source 순서와 owner 계약이 일치해 `ledger_sum=120`을 관찰한다.
- 틀린 예·반례
- 반례에서는 선행 guard·stable order·cleanup을 생략한다. 동결 경계: Docker·PostgreSQL 실행 환경이 필요하다.
- 착각 방지
- `원문 133–133줄`이 항목 전체 Green을 단독 증명한다고 읽지 않는다.
- 하지 않는 일
- 이 chunk가 책임지지 않는 범위: Docker·PostgreSQL 실행 환경이 필요하다.
- 다음 연결
- 다음 source chunk의 입력 또는 최종 marker/SQL oracle로 결과를 넘긴다.
반례
-
겉보기에는 맞지만 깨지는 예는?
-
backup 파일 존재만으로 복구 가능이라 한다
-
그 상태는 owner·입력·관찰 중 한 칸이 비어 있어.
-
수정한 뒤 같은 source와 hash로 다시 대조해.
STEP 08 / 13
실제 값 따라가기
같은 입력값이 어느 줄을 지나 어떤 결과가 되는지 추적합니다.
| 순서 | 들어온 값 | 코드가 하는 일 | 나온 값·상태 | 경계 |
|---|---|---|---|---|
| F06-T01 startup | Compose mode | up --wait db | container id | 부분 up도 finally 대상 |
| F06-T02 restore | W42 transcript+JSON | double validation | 3/120/0+rto | production RTO 아님 |
| F06-T03 publish | cleaned lifecycle | tmp→move | W22_RESTORE_GREEN | Container mode container는 caller 소유 |
책임 경계
-
이 항목의 마지막 책임선은?
-
직접 역할은 `정본 W22 disposable restore evidence producer`이야.
-
대표 경계는 `Docker·PostgreSQL 실행 환경이 필요하다`이야.
-
정본/비정본 label과 evidence owner까지 확인하면 끝이야.
STEP 09 / 13
GitHub·AWS·PowerShell·PostgreSQL 내부에서 벌어지는 일
GitHub·AWS·PowerShell·PostgreSQL에서 실제로 일어나는 일과 증명 범위를 구분합니다.
Compose mode에서 project ownership을 startup 전에 잡는다.
Container mode는 전달받은 container를 지우지 않는다.별도 source/target DB와 custom dump를 사용한다.
실서비스 backup 정책을 대신하지 않는다.inner result hash·timestamps·dump bytes를 outer JSON에 묶는다.
marker 한 줄만 저장하면 부족하다.STEP 10 / 13
흔한 착각과 틀린 예
그럴듯하지만 틀린 해석을 반례로 고칩니다.
❌ backup 파일 존재만으로 복구 가능이라 한다
왜 틀리나 정본 W22 disposable restore evidence producer의 owner·관찰·경계 중 적어도 하나를 건너뛴다.
바르게 읽기 allowlist와 transitive tool을 검사한다. 그리고 source의 실제 값과 hash를 다시 대조한다.
반례 반례에서는 `production RPO/RTO 보장이 아니다` 상태인데도 Green을 주장하게 된다.
❌ target DB allowlist를 넓힌다
왜 틀리나 정본 W22 disposable restore evidence producer의 owner·관찰·경계 중 적어도 하나를 건너뛴다.
바르게 읽기 Compose 또는 caller container를 선택한다. 그리고 source의 실제 값과 hash를 다시 대조한다.
반례 반례에서는 `run-w42-restore-drill.ps1에 transitive 의존한다` 상태인데도 Green을 주장하게 된다.
❌ W42 transcript만 보고 inner JSON을 생략한다
왜 틀리나 정본 W22 disposable restore evidence producer의 owner·관찰·경계 중 적어도 하나를 건너뛴다.
바르게 읽기 W42 restore 결과 3·120·0을 재검증한다. 그리고 source의 실제 값과 hash를 다시 대조한다.
반례 반례에서는 `허용 target DB 이름만 쓴다` 상태인데도 Green을 주장하게 된다.
❌ finally cleanup 전에 Green JSON을 발급한다
왜 틀리나 정본 W22 disposable restore evidence producer의 owner·관찰·경계 중 적어도 하나를 건너뛴다.
바르게 읽기 cleanup 뒤 restore-result.json을 atomic publish한다. 그리고 source의 실제 값과 hash를 다시 대조한다.
반례 반례에서는 `Docker·PostgreSQL 실행 환경이 필요하다` 상태인데도 Green을 주장하게 된다.
❌ 실측 초를 production RTO 보장으로 부른다
왜 틀리나 정본 W22 disposable restore evidence producer의 owner·관찰·경계 중 적어도 하나를 건너뛴다.
바르게 읽기 cleanup 뒤 restore-result.json을 atomic publish한다. 그리고 source의 실제 값과 hash를 다시 대조한다.
반례 반례에서는 `production RPO/RTO 보장이 아니다` 상태인데도 Green을 주장하게 된다.
STEP 11 / 13
이 코드가 보장하지 않는 것
이 코드가 책임지지 않는 일을 분리합니다.
production RPO/RTO 보장이 아니다
이 책임을 맡는 곳: 별도 외부/selector 실행run-w42-restore-drill.ps1에 transitive 의존한다
이 책임을 맡는 곳: secret·운영 정책허용 target DB 이름만 쓴다
이 책임을 맡는 곳: infrastructure·사람 검토Docker·PostgreSQL 실행 환경이 필요하다
이 책임을 맡는 곳: owner lifecycleSTEP 12 / 13
직접 다시 써보기
뜻 → 조각 → 전체 코드 순서로 다시 씁니다.
1단계 · 뜻부터 복원
다음 역할을 고정값과 미보장 경계까지 말한다: 고정 3행을 별도 DB에 dump/restore해 3·120·0과 cleanup을 검증하고 canonical restore-result.json을 atomic publish하는 W22 packaged owner다.
2단계 · 코드 조각 재조립
- 원문 1–12줄
- 원문 13–24줄
- 원문 25–36줄
- 원문 37–48줄
- 원문 49–60줄
- 원문 61–72줄
- 원문 73–84줄
- 원문 85–96줄
- 원문 97–108줄
- 원문 109–120줄
- 원문 121–132줄
- 원문 133–133줄
3단계 · 파일 전체 다시 쓰기
133개 물리 줄을 원본 순서로 복원하고 SHA-256 eb8cd1d71eeac0f1359441deaba4e0c596938f9d6dc3fc93a0319cf2594f6a25와 대조한다.
자가 점검
- 원본 source/template bytes를 바꾸지 않았는가?
- 외부 미실행과 local restore Green을 구분했는가?
- secret 원문을 evidence에 남기지 않았는가?
- D7 checked_at 충돌과 사람 검토 경계를 보았는가?
- Q35/Q36을 workbook 정본 답안이라고 부르지 않았는가?
STEP 13 / 13
전체 원본 source
감사로 고정한 전체 source를 가감 없이 확인합니다.
원문 정본 전체 source 확인하기
param(
[ValidateSet('Compose','Container')][string]$Mode = 'Compose',
[string]$ComposeProject = 'w22-restore-lab',
[string]$ContainerName = '',
[string]$EvidenceDir = 'evidence/w22',
[string]$TargetDb = 'financial_core_restore'
)
Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'
if ($TargetDb -cne 'financial_core_restore') {
throw 'W22 disposable target allowlist violation'
}
$root = Split-Path -Parent $PSScriptRoot
$evidence = if ([IO.Path]::IsPathRooted($EvidenceDir)) {
[IO.Path]::GetFullPath($EvidenceDir)
} else {
[IO.Path]::GetFullPath((Join-Path $root $EvidenceDir))
}
$tool = Join-Path $PSScriptRoot 'run-w42-restore-drill.ps1'
$compose = Join-Path $root 'compose.yaml'
$ownedCompose = $false
$composeCleanup = $false
$failure = $null
$body = $null
if (!(Test-Path -LiteralPath $tool -PathType Leaf)) {
throw 'W22 transitive W42 tool missing'
}
try {
if ($Mode -ceq 'Compose') {
if ($ContainerName) { throw 'W22 Compose mode rejects ContainerName' }
if ([string]::IsNullOrWhiteSpace($env:FCL_DB_PASSWORD)) {
$env:FCL_DB_PASSWORD = 'w22-disposable-password'
}
# Own the unique Compose project before startup so a partial `up`
# failure still reaches finally/down and cannot leak resources.
$ownedCompose = $true
& docker compose -f $compose -p $ComposeProject up -d --wait db
if ($LASTEXITCODE -ne 0) { throw "W22 compose up exit=$LASTEXITCODE" }
$ContainerName = (& docker compose -f $compose -p $ComposeProject ps -q db).Trim()
} elseif ([string]::IsNullOrWhiteSpace($ContainerName)) {
throw 'W22 Container mode requires ContainerName'
}
if ([string]::IsNullOrWhiteSpace($ContainerName)) {
throw 'W22 container resolution failed'
}
$output = @(
& powershell.exe -NoProfile -ExecutionPolicy Bypass -File $tool `
-Mode Container `
-ContainerName $ContainerName `
-AdminDatabase financial_core `
-Username app `
-TargetDb $TargetDb `
-EvidenceDir $evidence 2>&1
)
$nativeExit = $LASTEXITCODE
if ($nativeExit -ne 0) {
throw "W22 restore native exit=$nativeExit`n$($output -join "`n")"
}
$line = $output | Where-Object { $_ -match '^PASS W42_RESTORE ' } | Select-Object -Last 1
if (!$line -or $line -cnotmatch 'row_count=3 ledger_sum=120 mismatch=0 rto_seconds=([0-9]+(?:\.[0-9]+)?) source_dropped=1 target_dropped=1') {
throw "W22 transcript mismatch: $output"
}
$innerPath = Join-Path $evidence '5-restore-result.json'
if (!(Test-Path -LiteralPath $innerPath -PathType Leaf)) {
throw 'W22 inner restore result missing'
}
$inner = Get-Content -Raw -LiteralPath $innerPath | ConvertFrom-Json
if ([int]$inner.row_count -ne 3 -or [long]$inner.ledger_sum -ne 120 -or
[int]$inner.mismatch_count -ne 0 -or [long]$inner.dump_bytes -le 0) {
throw 'W22 inner restore invariant mismatch'
}
$start = [DateTimeOffset]::MinValue
$end = [DateTimeOffset]::MinValue
if (![DateTimeOffset]::TryParse([string]$inner.start_utc, [ref]$start) -or
![DateTimeOffset]::TryParse([string]$inner.end_utc, [ref]$end) -or $end -lt $start) {
throw 'W22 inner restore timestamps invalid'
}
$body = [ordered]@{
owner = 'W22'
run_id = [guid]::NewGuid().ToString('N')
started_at_utc = $start.ToString('o')
completed_at_utc = $end.ToString('o')
source_db = 'financial_core_restore_source'
target_db = $TargetDb
fixture_schema = 'restore_probe_v1'
row_count = 3
ledger_sum = 120
mismatch = 0
rto_seconds = [double]$inner.rto_seconds
dump_bytes = [long]$inner.dump_bytes
source_dropped = 1
target_dropped = 1
cleanup = 1
native_exit = 0
inner_result_path = 'evidence/w22/5-restore-result.json'
inner_result_sha256 = (Get-FileHash -LiteralPath $innerPath -Algorithm SHA256).Hash.ToLowerInvariant()
}
} catch {
$failure = $_
} finally {
if ($ownedCompose) {
& docker compose -f $compose -p $ComposeProject down -v --remove-orphans | Out-Null
$composeCleanup = ($LASTEXITCODE -eq 0)
} else {
$composeCleanup = $true
}
}
if (!$composeCleanup) {
if ($null -ne $failure) {
throw "W22 restore failed and owned Compose cleanup failed: $($failure.Exception.Message)"
}
throw 'W22 owned Compose cleanup failed'
}
if ($null -ne $failure) { throw $failure }
if ($null -eq $body) { throw 'W22 restore produced no canonical result' }
$body['compose_cleanup'] = if ($ownedCompose) { 1 } else { 'not-owned' }
New-Item -ItemType Directory -Force $evidence | Out-Null
$resultPath = Join-Path $evidence 'restore-result.json'
$temporary = "$resultPath.tmp"
$body | ConvertTo-Json -Depth 5 | Set-Content -Encoding utf8 -LiteralPath $temporary
Move-Item -LiteralPath $temporary -Destination $resultPath -Force
"W22_RESTORE_GREEN row_count=3 ledger_sum=120 mismatch=0 rto_seconds=$($body.rto_seconds) cleanup=1 native_exit=0"
07비용·teardown inventory — checked_at 계약까지 닫기
illustrative/json/W22-D7-resource-inventory.json
학습용 예시 · PDF JSON schema/worksheet · 정본 답안 아님 · 비실행 · 학습용 예시 · 정본 답안 아님 · W22-F0734줄 연결34줄 번역4 chunks
비용·teardown inventory — checked_at 계약까지 닫기
illustrative/json/W22-D7-resource-inventory.json
학습용 예시 · PDF JSON schema/worksheet · 정본 답안 아님 · 비실행 · 학습용 예시 · 정본 답안 아님 · W22-F07STEP 01 / 13
오늘 이 코드에서 해결할 문제
무엇을 이해해야 하는지 질문부터 잡습니다.
EC2/ECS·RDS·ECR·NAT와 budget alarm을 teardown 뒤 다시 inventory하는 D7 worksheet 보완 예시다.
- `MANUAL_REVIEW_REQUIRED`은 어느 줄에서 생길까?
- 입력→guard→관찰→cleanup 순서는 무엇인가?
- local owner와 external human review는 누구인가?
- 직접 관찰하지 않은 Green은 무엇인가?
- 반례는 `example 값이 남으면 실제 inventory가 아니다`이라는 경계와 어떻게 연결되는가?
MANUAL_REVIEW_REQUIREDap-northeast-2resourceschecked_atbudget_alarmSTEP 02 / 13
아주 짧게: 이 코드는 왜 필요할까?
웹소설 대신 이 코드가 필요한 이유만 두 문단으로 쉽게 봅니다.
STARRY가 GitHub run표·AWS 출입증·DB 복구 영수증·SQL 결과표를 서로 다른 칸에 놓는다.
비용·teardown inventory — checked_at 계약까지 닫기 ― 증거 흐름으로 바꾸기
EC2/ECS·RDS·ECR·NAT와 budget alarm을 teardown 뒤 다시 inventory하는 D7 worksheet 보완 예시다.
핵심값 MANUAL_REVIEW_REQUIRED, ap-northeast-2, resources, checked_at, budget_alarm을 원본 줄로 따라가되, `example 값이 남으면 실제 inventory가 아니다`까지 함께 표시해 Green 범위를 부풀리지 않는다.
딱 여기까지만 비유는 owner와 순서를 기억하게 할 뿐 외부 실행·AWS 계정 상태·PostgreSQL restore·SQL 결과를 자동 증명하지 않는다.
STEP 03 / 13
초등학생도 이해하는 설명
생활 비유와 실제 코드의 경계를 함께 확인합니다.
원문 1–10줄
1~10줄을 한 덩어리로 읽어 1번째 움직임을 본다. EC2/ECS·RDS·ECR·NAT와 budget alarm을 teardown 뒤 다시 inventory하는 D7 worksheet 보완 예시다.
- 코드 연결
1~10줄- 비유
- 여행 전 예산 봉투를 만들고, 돌아온 뒤 대여품 목록과 반납 시각을 다시 적어 남은 비용을 확인하는 teardown 장부
- 비유의 끝
- example 값이 남으면 실제 inventory가 아니다
원문 11–20줄
11~20줄을 한 덩어리로 읽어 2번째 움직임을 본다. EC2/ECS·RDS·ECR·NAT와 budget alarm을 teardown 뒤 다시 inventory하는 D7 worksheet 보완 예시다.
- 코드 연결
11~20줄- 비유
- 여행 전 예산 봉투를 만들고, 돌아온 뒤 대여품 목록과 반납 시각을 다시 적어 남은 비용을 확인하는 teardown 장부
- 비유의 끝
- PDF worksheet에는 validator 필수 checked_at이 빠져 있다
원문 21–30줄
21~30줄을 한 덩어리로 읽어 3번째 움직임을 본다. EC2/ECS·RDS·ECR·NAT와 budget alarm을 teardown 뒤 다시 inventory하는 D7 worksheet 보완 예시다.
- 코드 연결
21~30줄- 비유
- 여행 전 예산 봉투를 만들고, 돌아온 뒤 대여품 목록과 반납 시각을 다시 적어 남은 비용을 확인하는 teardown 장부
- 비유의 끝
- 의도적 보존 resource는 이유와 만료일이 필요하다
문제의 첫 장면
-
첫 고정값은 `MANUAL_REVIEW_REQUIRED` 맞아?
-
EC2/ECS·RDS·ECR·NAT와 budget alarm을 teardown 뒤 다시 inventory하는 D7 worksheet 보완 예시다.
-
원문에서 `MANUAL_REVIEW_REQUIRED`이 생기는 위치를 찾자.
-
그리고 `example 값이 남으면 실제 inventory가 아니다`도 같이 적어.
입력에서 결과까지
-
`ap-northeast-2`은 언제 생겨?
-
budget·owner·expiresAt을 먼저 만든다. → 생성 전 inventory를 저장한다.
-
실습 뒤 resource를 삭제·보존 판정한다. → checked_at과 screenshot hash로 teardown 후 상태를 묶는다.
-
관찰값과 `PDF worksheet에는 validator 필수 checked_at이 빠져 있다`을 분리하면 돼.
STEP 04 / 13
비유 ↔ 코드 전체 연결표
감사 규칙상 연결 대상인 원본 34줄을 빠짐없이 연결합니다.
| 줄 | 정확한 원본 줄 | STARRY 비유 | 실제 뜻·입력·결과·한계 |
|---|---|---|---|
| 1줄F07-L01 | { |
여행 전 예산 봉투를 만들고, 돌아온 뒤 대여품 목록과 반납 시각을 다시 적어 남은 비용을 확인하는 teardown 장부 | 현재 object·array·block 또는 query 범위를 열거나 닫아 구조를 유지한다.
|
| 2줄F07-L02 | "_provenance": |
여행 전 예산 봉투를 만들고, 돌아온 뒤 대여품 목록과 반납 시각을 다시 적어 남은 비용을 확인하는 teardown 장부 | 비용·resource teardown worksheet에서 `"_provenance": "학습용 예시 · PDF 비용·teardown workshe` field·값 또는 assignment를 다음 단계에 전달한다.
|
| 3줄F07-L03 | "status": |
여행 전 예산 봉투를 만들고, 돌아온 뒤 대여품 목록과 반납 시각을 다시 적어 남은 비용을 확인하는 teardown 장부 | 자동 shape/hash 검사 뒤에도 사람의 의미 검토가 남았음을 고정한다.
|
| 4줄F07-L04 | "region": |
여행 전 예산 봉투를 만들고, 돌아온 뒤 대여품 목록과 반납 시각을 다시 적어 남은 비용을 확인하는 teardown 장부 | 비용·resource teardown worksheet에서 `"region": "ap-northeast-2",` field·값 또는 assignment를 다음 단계에 전달한다.
|
| 5줄F07-L05 | "checked_at": |
여행 전 예산 봉투를 만들고, 돌아온 뒤 대여품 목록과 반납 시각을 다시 적어 남은 비용을 확인하는 teardown 장부 | D7 validator와 호환되도록 inventory 관찰 시각 field를 둔다.
|
| 6줄F07-L06 | "resources": |
여행 전 예산 봉투를 만들고, 돌아온 뒤 대여품 목록과 반납 시각을 다시 적어 남은 비용을 확인하는 teardown 장부 | teardown 전후 대조할 AWS resource 목록 배열을 연다.
|
| 7줄F07-L07 | { |
여행 전 예산 봉투를 만들고, 돌아온 뒤 대여품 목록과 반납 시각을 다시 적어 남은 비용을 확인하는 teardown 장부 | 현재 object·array·block 또는 query 범위를 열거나 닫아 구조를 유지한다.
|
| 8줄F07-L08 | "type": |
여행 전 예산 봉투를 만들고, 돌아온 뒤 대여품 목록과 반납 시각을 다시 적어 남은 비용을 확인하는 teardown 장부 | 비용·resource teardown worksheet에서 `"type": "EC2_OR_ECS",` field·값 또는 assignment를 다음 단계에 전달한다.
|
| 9줄F07-L09 | "id": |
여행 전 예산 봉투를 만들고, 돌아온 뒤 대여품 목록과 반납 시각을 다시 적어 남은 비용을 확인하는 teardown 장부 | 비용·resource teardown worksheet에서 `"id": "EXAMPLE_RESOURCE_ID",` field·값 또는 assignment를 다음 단계에 전달한다.
|
| 10줄F07-L10 | "state": |
여행 전 예산 봉투를 만들고, 돌아온 뒤 대여품 목록과 반납 시각을 다시 적어 남은 비용을 확인하는 teardown 장부 | 비용·resource teardown worksheet에서 `"state": "terminated-or-zero-tasks"` field·값 또는 assignment를 다음 단계에 전달한다.
|
| 11줄F07-L11 | }, |
여행 전 예산 봉투를 만들고, 돌아온 뒤 대여품 목록과 반납 시각을 다시 적어 남은 비용을 확인하는 teardown 장부 | 현재 object·array·block 또는 query 범위를 열거나 닫아 구조를 유지한다.
|
| 12줄F07-L12 | { |
여행 전 예산 봉투를 만들고, 돌아온 뒤 대여품 목록과 반납 시각을 다시 적어 남은 비용을 확인하는 teardown 장부 | 현재 object·array·block 또는 query 범위를 열거나 닫아 구조를 유지한다.
|
| 13줄F07-L13 | "type": |
여행 전 예산 봉투를 만들고, 돌아온 뒤 대여품 목록과 반납 시각을 다시 적어 남은 비용을 확인하는 teardown 장부 | private PostgreSQL 5432와 application SG 사이의 DB 경계를 표현한다.
|
| 14줄F07-L14 | "id": |
여행 전 예산 봉투를 만들고, 돌아온 뒤 대여품 목록과 반납 시각을 다시 적어 남은 비용을 확인하는 teardown 장부 | 비용·resource teardown worksheet에서 `"id": "EXAMPLE_RESOURCE_ID",` field·값 또는 assignment를 다음 단계에 전달한다.
|
| 15줄F07-L15 | "state": |
여행 전 예산 봉투를 만들고, 돌아온 뒤 대여품 목록과 반납 시각을 다시 적어 남은 비용을 확인하는 teardown 장부 | 비용·resource teardown worksheet에서 `"state": "deleted-or-approved-retained"` field·값 또는 assignment를 다음 단계에 전달한다.
|
| 16줄F07-L16 | }, |
여행 전 예산 봉투를 만들고, 돌아온 뒤 대여품 목록과 반납 시각을 다시 적어 남은 비용을 확인하는 teardown 장부 | 현재 object·array·block 또는 query 범위를 열거나 닫아 구조를 유지한다.
|
| 17줄F07-L17 | { |
여행 전 예산 봉투를 만들고, 돌아온 뒤 대여품 목록과 반납 시각을 다시 적어 남은 비용을 확인하는 teardown 장부 | 현재 object·array·block 또는 query 범위를 열거나 닫아 구조를 유지한다.
|
| 18줄F07-L18 | "type": |
여행 전 예산 봉투를 만들고, 돌아온 뒤 대여품 목록과 반납 시각을 다시 적어 남은 비용을 확인하는 teardown 장부 | 비용·resource teardown worksheet에서 `"type": "ECR",` field·값 또는 assignment를 다음 단계에 전달한다.
|
| 19줄F07-L19 | "id": |
여행 전 예산 봉투를 만들고, 돌아온 뒤 대여품 목록과 반납 시각을 다시 적어 남은 비용을 확인하는 teardown 장부 | 비용·resource teardown worksheet에서 `"id": "EXAMPLE_REPOSITORY",` field·값 또는 assignment를 다음 단계에 전달한다.
|
| 20줄F07-L20 | "digest": |
여행 전 예산 봉투를 만들고, 돌아온 뒤 대여품 목록과 반납 시각을 다시 적어 남은 비용을 확인하는 teardown 장부 | 현재 file bytes를 64-hex SHA-256 값과 결박하는 field 또는 검사를 다룬다.
|
| 21줄F07-L21 | }, |
여행 전 예산 봉투를 만들고, 돌아온 뒤 대여품 목록과 반납 시각을 다시 적어 남은 비용을 확인하는 teardown 장부 | 현재 object·array·block 또는 query 범위를 열거나 닫아 구조를 유지한다.
|
| 22줄F07-L22 | { |
여행 전 예산 봉투를 만들고, 돌아온 뒤 대여품 목록과 반납 시각을 다시 적어 남은 비용을 확인하는 teardown 장부 | 현재 object·array·block 또는 query 범위를 열거나 닫아 구조를 유지한다.
|
| 23줄F07-L23 | "type": |
여행 전 예산 봉투를 만들고, 돌아온 뒤 대여품 목록과 반납 시각을 다시 적어 남은 비용을 확인하는 teardown 장부 | 비용·resource teardown worksheet에서 `"type": "NAT_GATEWAY",` field·값 또는 assignment를 다음 단계에 전달한다.
|
| 24줄F07-L24 | "id": |
여행 전 예산 봉투를 만들고, 돌아온 뒤 대여품 목록과 반납 시각을 다시 적어 남은 비용을 확인하는 teardown 장부 | 비용·resource teardown worksheet에서 `"id": "EXAMPLE_IF_CREATED",` field·값 또는 assignment를 다음 단계에 전달한다.
|
| 25줄F07-L25 | "state": |
여행 전 예산 봉투를 만들고, 돌아온 뒤 대여품 목록과 반납 시각을 다시 적어 남은 비용을 확인하는 teardown 장부 | 비용·resource teardown worksheet에서 `"state": "deleted"` field·값 또는 assignment를 다음 단계에 전달한다.
|
| 26줄F07-L26 | } |
여행 전 예산 봉투를 만들고, 돌아온 뒤 대여품 목록과 반납 시각을 다시 적어 남은 비용을 확인하는 teardown 장부 | 현재 object·array·block 또는 query 범위를 열거나 닫아 구조를 유지한다.
|
| 27줄F07-L27 | ], |
여행 전 예산 봉투를 만들고, 돌아온 뒤 대여품 목록과 반납 시각을 다시 적어 남은 비용을 확인하는 teardown 장부 | 현재 object·array·block 또는 query 범위를 열거나 닫아 구조를 유지한다.
|
| 28줄F07-L28 | "budget_alarm": |
여행 전 예산 봉투를 만들고, 돌아온 뒤 대여품 목록과 반납 시각을 다시 적어 남은 비용을 확인하는 teardown 장부 | resource 생성 전 비용 경계와 알림 상태를 기록한다.
|
| 29줄F07-L29 | "currency": |
여행 전 예산 봉투를 만들고, 돌아온 뒤 대여품 목록과 반납 시각을 다시 적어 남은 비용을 확인하는 teardown 장부 | 비용·resource teardown worksheet에서 `"currency": "USD",` field·값 또는 assignment를 다음 단계에 전달한다.
|
| 30줄F07-L30 | "threshold": |
여행 전 예산 봉투를 만들고, 돌아온 뒤 대여품 목록과 반납 시각을 다시 적어 남은 비용을 확인하는 teardown 장부 | 비용·resource teardown worksheet에서 `"threshold": "EXAMPLE_LIMIT",` field·값 또는 assignment를 다음 단계에 전달한다.
|
| 31줄F07-L31 | "notification_tested": |
여행 전 예산 봉투를 만들고, 돌아온 뒤 대여품 목록과 반납 시각을 다시 적어 남은 비용을 확인하는 teardown 장부 | 비용·resource teardown worksheet에서 `"notification_tested": false` field·값 또는 assignment를 다음 단계에 전달한다.
|
| 32줄F07-L32 | }, |
여행 전 예산 봉투를 만들고, 돌아온 뒤 대여품 목록과 반납 시각을 다시 적어 남은 비용을 확인하는 teardown 장부 | 현재 object·array·block 또는 query 범위를 열거나 닫아 구조를 유지한다.
|
| 33줄F07-L33 | "official_console_screenshot_sha256": |
여행 전 예산 봉투를 만들고, 돌아온 뒤 대여품 목록과 반납 시각을 다시 적어 남은 비용을 확인하는 teardown 장부 | 현재 file bytes를 64-hex SHA-256 값과 결박하는 field 또는 검사를 다룬다.
|
| 34줄F07-L34 | } |
여행 전 예산 봉투를 만들고, 돌아온 뒤 대여품 목록과 반납 시각을 다시 적어 남은 비용을 확인하는 teardown 장부 | 현재 object·array·block 또는 query 범위를 열거나 닫아 구조를 유지한다.
|
Green 범위
-
marker나 파일이 보이면 전부 성공이야?
-
아니. source가 직접 검증한 범위만 말해야 해.
-
직접 연결되는 대표 값은 `budget_alarm`이야.
-
`의도적 보존 resource는 이유와 만료일이 필요하다`는 별도 증거가 필요해.
STEP 05 / 13
원본 코드 조각
원본을 4개 의미 조각으로 나누어 그대로 확인합니다.
파일을 한꺼번에 외우지 않고 실행 의미가 이어지는 작은 조각으로 봅니다. 아래 코드는 prompt·fixture·가정을 밝힌 학습용 예시 source이며, 제공 정본 답안이 아닙니다.
{
"_provenance": "학습용 예시 · PDF 비용·teardown worksheet 보완본 · 정본 답안 아님 · 비실행",
"status": "MANUAL_REVIEW_REQUIRED",
"region": "ap-northeast-2",
"checked_at": "EXAMPLE_UTC_TIMESTAMP_REQUIRED_BY_D7_VALIDATOR",
"resources": [
{
"type": "EC2_OR_ECS",
"id": "EXAMPLE_RESOURCE_ID",
"state": "terminated-or-zero-tasks"
},
{
"type": "RDS",
"id": "EXAMPLE_RESOURCE_ID",
"state": "deleted-or-approved-retained"
},
{
"type": "ECR",
"id": "EXAMPLE_REPOSITORY",
"digest": "sha256:EXAMPLE_DIGEST"
},
{
"type": "NAT_GATEWAY",
"id": "EXAMPLE_IF_CREATED",
"state": "deleted"
}
],
"budget_alarm": {
"currency": "USD",
"threshold": "EXAMPLE_LIMIT",
"notification_tested": false
},
"official_console_screenshot_sha256": "EXAMPLE_AFTER_REAL_EXTERNAL_RUN"
}
STEP 06 / 13
코드 한 줄씩 한국어로 번역
비어 있지 않은 34줄을 모두 한국어로 옮깁니다.
비어 있지 않은 원본 줄은 하나도 생략하지 않습니다.
| 줄 | 원본 | 한국어 번역 |
|---|---|---|
| 1 | { | 현재 object·array·block 또는 query 범위를 열거나 닫아 구조를 유지한다. |
| 2 | "_provenance": "학습용 예시 · PDF 비용·teardown worksheet 보완본 · 정본 답안 아님 · 비실행", | 비용·resource teardown worksheet에서 `"_provenance": "학습용 예시 · PDF 비용·teardown workshe` field·값 또는 assignment를 다음 단계에 전달한다. |
| 3 | "status": "MANUAL_REVIEW_REQUIRED", | 자동 shape/hash 검사 뒤에도 사람의 의미 검토가 남았음을 고정한다. |
| 4 | "region": "ap-northeast-2", | 비용·resource teardown worksheet에서 `"region": "ap-northeast-2",` field·값 또는 assignment를 다음 단계에 전달한다. |
| 5 | "checked_at": "EXAMPLE_UTC_TIMESTAMP_REQUIRED_BY_D7_VALIDATOR", | D7 validator와 호환되도록 inventory 관찰 시각 field를 둔다. |
| 6 | "resources": [ | teardown 전후 대조할 AWS resource 목록 배열을 연다. |
| 7 | { | 현재 object·array·block 또는 query 범위를 열거나 닫아 구조를 유지한다. |
| 8 | "type": "EC2_OR_ECS", | 비용·resource teardown worksheet에서 `"type": "EC2_OR_ECS",` field·값 또는 assignment를 다음 단계에 전달한다. |
| 9 | "id": "EXAMPLE_RESOURCE_ID", | 비용·resource teardown worksheet에서 `"id": "EXAMPLE_RESOURCE_ID",` field·값 또는 assignment를 다음 단계에 전달한다. |
| 10 | "state": "terminated-or-zero-tasks" | 비용·resource teardown worksheet에서 `"state": "terminated-or-zero-tasks"` field·값 또는 assignment를 다음 단계에 전달한다. |
| 11 | }, | 현재 object·array·block 또는 query 범위를 열거나 닫아 구조를 유지한다. |
| 12 | { | 현재 object·array·block 또는 query 범위를 열거나 닫아 구조를 유지한다. |
| 13 | "type": "RDS", | private PostgreSQL 5432와 application SG 사이의 DB 경계를 표현한다. |
| 14 | "id": "EXAMPLE_RESOURCE_ID", | 비용·resource teardown worksheet에서 `"id": "EXAMPLE_RESOURCE_ID",` field·값 또는 assignment를 다음 단계에 전달한다. |
| 15 | "state": "deleted-or-approved-retained" | 비용·resource teardown worksheet에서 `"state": "deleted-or-approved-retained"` field·값 또는 assignment를 다음 단계에 전달한다. |
| 16 | }, | 현재 object·array·block 또는 query 범위를 열거나 닫아 구조를 유지한다. |
| 17 | { | 현재 object·array·block 또는 query 범위를 열거나 닫아 구조를 유지한다. |
| 18 | "type": "ECR", | 비용·resource teardown worksheet에서 `"type": "ECR",` field·값 또는 assignment를 다음 단계에 전달한다. |
| 19 | "id": "EXAMPLE_REPOSITORY", | 비용·resource teardown worksheet에서 `"id": "EXAMPLE_REPOSITORY",` field·값 또는 assignment를 다음 단계에 전달한다. |
| 20 | "digest": "sha256:EXAMPLE_DIGEST" | 현재 file bytes를 64-hex SHA-256 값과 결박하는 field 또는 검사를 다룬다. |
| 21 | }, | 현재 object·array·block 또는 query 범위를 열거나 닫아 구조를 유지한다. |
| 22 | { | 현재 object·array·block 또는 query 범위를 열거나 닫아 구조를 유지한다. |
| 23 | "type": "NAT_GATEWAY", | 비용·resource teardown worksheet에서 `"type": "NAT_GATEWAY",` field·값 또는 assignment를 다음 단계에 전달한다. |
| 24 | "id": "EXAMPLE_IF_CREATED", | 비용·resource teardown worksheet에서 `"id": "EXAMPLE_IF_CREATED",` field·값 또는 assignment를 다음 단계에 전달한다. |
| 25 | "state": "deleted" | 비용·resource teardown worksheet에서 `"state": "deleted"` field·값 또는 assignment를 다음 단계에 전달한다. |
| 26 | } | 현재 object·array·block 또는 query 범위를 열거나 닫아 구조를 유지한다. |
| 27 | ], | 현재 object·array·block 또는 query 범위를 열거나 닫아 구조를 유지한다. |
| 28 | "budget_alarm": { | resource 생성 전 비용 경계와 알림 상태를 기록한다. |
| 29 | "currency": "USD", | 비용·resource teardown worksheet에서 `"currency": "USD",` field·값 또는 assignment를 다음 단계에 전달한다. |
| 30 | "threshold": "EXAMPLE_LIMIT", | 비용·resource teardown worksheet에서 `"threshold": "EXAMPLE_LIMIT",` field·값 또는 assignment를 다음 단계에 전달한다. |
| 31 | "notification_tested": false | 비용·resource teardown worksheet에서 `"notification_tested": false` field·값 또는 assignment를 다음 단계에 전달한다. |
| 32 | }, | 현재 object·array·block 또는 query 범위를 열거나 닫아 구조를 유지한다. |
| 33 | "official_console_screenshot_sha256": "EXAMPLE_AFTER_REAL_EXTERNAL_RUN" | 현재 file bytes를 64-hex SHA-256 값과 결박하는 field 또는 검사를 다룬다. |
| 34 | } | 현재 object·array·block 또는 query 범위를 열거나 닫아 구조를 유지한다. |
STEP 07 / 13
기존 수준의 한 줄 읽기·문법 해부
쉬운 설명 다음에 문법과 실행 순서를 정밀하게 읽습니다.
한 줄로 읽기EC2/ECS·RDS·ECR·NAT와 budget alarm을 teardown 뒤 다시 inventory하는 D7 worksheet 보완 예시다. 다만 example 값이 남으면 실제 inventory가 아니다
문법 해부
- JSON `resources` 배열이 resource type·id·state를 한 행씩 기록한다.
- 인접 D7 validator가 `resources`뿐 아니라 top-level `checked_at`도 요구한다.
실행 순서
- budget·owner·expiresAt을 먼저 만든다.
- 생성 전 inventory를 저장한다.
- 실습 뒤 resource를 삭제·보존 판정한다.
- checked_at과 screenshot hash로 teardown 후 상태를 묶는다.
W22 조각별 정밀 해설
F07-C01 · 원문 1–10줄
- 문법 해부
- 1~10줄의 `원문 1–10줄`을 입력·guard·관찰·cleanup 단계로 나눈다.
- 실제 값 추적
- 항목 전체 흐름에 연결해 `MANUAL_REVIEW_REQUIRED`을 대조한다. 이 값이 chunk 단독 산출이라는 뜻은 아니다.
- 정상 예
- 정상 예에서는 source 순서와 owner 계약이 일치해 `MANUAL_REVIEW_REQUIRED`을 관찰한다.
- 틀린 예·반례
- 반례에서는 선행 guard·stable order·cleanup을 생략한다. 동결 경계: example 값이 남으면 실제 inventory가 아니다.
- 착각 방지
- `원문 1–10줄`이 항목 전체 Green을 단독 증명한다고 읽지 않는다.
- 하지 않는 일
- 이 chunk가 책임지지 않는 범위: example 값이 남으면 실제 inventory가 아니다.
- 다음 연결
- 다음 source chunk의 입력 또는 최종 marker/SQL oracle로 결과를 넘긴다.
F07-C02 · 원문 11–20줄
- 문법 해부
- 11~20줄의 `원문 11–20줄`을 입력·guard·관찰·cleanup 단계로 나눈다.
- 실제 값 추적
- 항목 전체 흐름에 연결해 `ap-northeast-2`을 대조한다. 이 값이 chunk 단독 산출이라는 뜻은 아니다.
- 정상 예
- 정상 예에서는 source 순서와 owner 계약이 일치해 `ap-northeast-2`을 관찰한다.
- 틀린 예·반례
- 반례에서는 선행 guard·stable order·cleanup을 생략한다. 동결 경계: PDF worksheet에는 validator 필수 checked_at이 빠져 있다.
- 착각 방지
- `원문 11–20줄`이 항목 전체 Green을 단독 증명한다고 읽지 않는다.
- 하지 않는 일
- 이 chunk가 책임지지 않는 범위: PDF worksheet에는 validator 필수 checked_at이 빠져 있다.
- 다음 연결
- 다음 source chunk의 입력 또는 최종 marker/SQL oracle로 결과를 넘긴다.
F07-C03 · 원문 21–30줄
- 문법 해부
- 21~30줄의 `원문 21–30줄`을 입력·guard·관찰·cleanup 단계로 나눈다.
- 실제 값 추적
- 항목 전체 흐름에 연결해 `resources`을 대조한다. 이 값이 chunk 단독 산출이라는 뜻은 아니다.
- 정상 예
- 정상 예에서는 source 순서와 owner 계약이 일치해 `resources`을 관찰한다.
- 틀린 예·반례
- 반례에서는 선행 guard·stable order·cleanup을 생략한다. 동결 경계: 의도적 보존 resource는 이유와 만료일이 필요하다.
- 착각 방지
- `원문 21–30줄`이 항목 전체 Green을 단독 증명한다고 읽지 않는다.
- 하지 않는 일
- 이 chunk가 책임지지 않는 범위: 의도적 보존 resource는 이유와 만료일이 필요하다.
- 다음 연결
- 다음 source chunk의 입력 또는 최종 marker/SQL oracle로 결과를 넘긴다.
F07-C04 · 원문 31–34줄
- 문법 해부
- 31~34줄의 `원문 31–34줄`을 입력·guard·관찰·cleanup 단계로 나눈다.
- 실제 값 추적
- 항목 전체 흐름에 연결해 `checked_at`을 대조한다. 이 값이 chunk 단독 산출이라는 뜻은 아니다.
- 정상 예
- 정상 예에서는 source 순서와 owner 계약이 일치해 `checked_at`을 관찰한다.
- 틀린 예·반례
- 반례에서는 선행 guard·stable order·cleanup을 생략한다. 동결 경계: console 화면은 exact screenshot hash와 묶어야 한다.
- 착각 방지
- `원문 31–34줄`이 항목 전체 Green을 단독 증명한다고 읽지 않는다.
- 하지 않는 일
- 이 chunk가 책임지지 않는 범위: console 화면은 exact screenshot hash와 묶어야 한다.
- 다음 연결
- 다음 source chunk의 입력 또는 최종 marker/SQL oracle로 결과를 넘긴다.
반례
-
겉보기에는 맞지만 깨지는 예는?
-
resource를 만든 뒤 budget을 설정한다
-
그 상태는 owner·입력·관찰 중 한 칸이 비어 있어.
-
수정한 뒤 같은 source와 hash로 다시 대조해.
STEP 08 / 13
실제 값 따라가기
같은 입력값이 어느 줄을 지나 어떤 결과가 되는지 추적합니다.
| 순서 | 들어온 값 | 코드가 하는 일 | 나온 값·상태 | 경계 |
|---|---|---|---|---|
| F07-T01 before | tagged account | inventory | planned resources | cost gate 먼저 |
| F07-T02 after | ALB/RDS/NAT/EIP | delete/recheck | retained only | 보존 이유·만료일 |
| F07-T03 binding | console capture | SHA-256 | manual review | worksheet 자체는 외부 실행 아님 |
책임 경계
-
이 항목의 마지막 책임선은?
-
직접 역할은 `비용·resource teardown worksheet`이야.
-
대표 경계는 `console 화면은 exact screenshot hash와 묶어야 한다`이야.
-
정본/비정본 label과 evidence owner까지 확인하면 끝이야.
STEP 09 / 13
GitHub·AWS·PowerShell·PostgreSQL 내부에서 벌어지는 일
GitHub·AWS·PowerShell·PostgreSQL에서 실제로 일어나는 일과 증명 범위를 구분합니다.
project tag 기준 resource 목록을 찾는다.
모든 untagged 비용 resource를 보장하지 않는다.budget alarm이 비용 guardrail을 제공한다.
실시간 hard stop은 아니다.resources와 checked_at shape를 검사한다.
PDF p746 예시는 checked_at이 빠져 보완이 필요하다.STEP 10 / 13
흔한 착각과 틀린 예
그럴듯하지만 틀린 해석을 반례로 고칩니다.
❌ resource를 만든 뒤 budget을 설정한다
왜 틀리나 비용·resource teardown worksheet의 owner·관찰·경계 중 적어도 하나를 건너뛴다.
바르게 읽기 budget·owner·expiresAt을 먼저 만든다. 그리고 source의 실제 값과 hash를 다시 대조한다.
반례 반례에서는 `example 값이 남으면 실제 inventory가 아니다` 상태인데도 Green을 주장하게 된다.
❌ NAT Gateway·EIP를 inventory에서 뺀다
왜 틀리나 비용·resource teardown worksheet의 owner·관찰·경계 중 적어도 하나를 건너뛴다.
바르게 읽기 생성 전 inventory를 저장한다. 그리고 source의 실제 값과 hash를 다시 대조한다.
반례 반례에서는 `PDF worksheet에는 validator 필수 checked_at이 빠져 있다` 상태인데도 Green을 주장하게 된다.
❌ retained resource 이유와 만료일을 비운다
왜 틀리나 비용·resource teardown worksheet의 owner·관찰·경계 중 적어도 하나를 건너뛴다.
바르게 읽기 실습 뒤 resource를 삭제·보존 판정한다. 그리고 source의 실제 값과 hash를 다시 대조한다.
반례 반례에서는 `의도적 보존 resource는 이유와 만료일이 필요하다` 상태인데도 Green을 주장하게 된다.
❌ p746 JSON을 그대로 복사해 checked_at을 누락한다
왜 틀리나 비용·resource teardown worksheet의 owner·관찰·경계 중 적어도 하나를 건너뛴다.
바르게 읽기 checked_at과 screenshot hash로 teardown 후 상태를 묶는다. 그리고 source의 실제 값과 hash를 다시 대조한다.
반례 반례에서는 `console 화면은 exact screenshot hash와 묶어야 한다` 상태인데도 Green을 주장하게 된다.
❌ tag 결과가 비면 계정 전체 비용이 0이라고 단정한다
왜 틀리나 비용·resource teardown worksheet의 owner·관찰·경계 중 적어도 하나를 건너뛴다.
바르게 읽기 checked_at과 screenshot hash로 teardown 후 상태를 묶는다. 그리고 source의 실제 값과 hash를 다시 대조한다.
반례 반례에서는 `example 값이 남으면 실제 inventory가 아니다` 상태인데도 Green을 주장하게 된다.
STEP 11 / 13
이 코드가 보장하지 않는 것
이 코드가 책임지지 않는 일을 분리합니다.
example 값이 남으면 실제 inventory가 아니다
이 책임을 맡는 곳: 별도 외부/selector 실행PDF worksheet에는 validator 필수 checked_at이 빠져 있다
이 책임을 맡는 곳: secret·운영 정책의도적 보존 resource는 이유와 만료일이 필요하다
이 책임을 맡는 곳: infrastructure·사람 검토console 화면은 exact screenshot hash와 묶어야 한다
이 책임을 맡는 곳: owner lifecycleSTEP 12 / 13
직접 다시 써보기
뜻 → 조각 → 전체 코드 순서로 다시 씁니다.
1단계 · 뜻부터 복원
다음 역할을 고정값과 미보장 경계까지 말한다: EC2/ECS·RDS·ECR·NAT와 budget alarm을 teardown 뒤 다시 inventory하는 D7 worksheet 보완 예시다.
2단계 · 코드 조각 재조립
- 원문 1–10줄
- 원문 11–20줄
- 원문 21–30줄
- 원문 31–34줄
3단계 · 파일 전체 다시 쓰기
34개 물리 줄을 원본 순서로 복원하고 SHA-256 a2d8f62245a5a60285538dfd624b95f13181ce16fc447632f8942c235de92ce4와 대조한다.
자가 점검
- 원본 source/template bytes를 바꾸지 않았는가?
- 외부 미실행과 local restore Green을 구분했는가?
- secret 원문을 evidence에 남기지 않았는가?
- D7 checked_at 충돌과 사람 검토 경계를 보았는가?
- Q35/Q36을 workbook 정본 답안이라고 부르지 않았는가?
STEP 13 / 13
전체 원본 source
감사로 고정한 전체 source를 가감 없이 확인합니다.
학습용 예시 전체 확인하기 · 정본 답안 아님
{
"_provenance": "학습용 예시 · PDF 비용·teardown worksheet 보완본 · 정본 답안 아님 · 비실행",
"status": "MANUAL_REVIEW_REQUIRED",
"region": "ap-northeast-2",
"checked_at": "EXAMPLE_UTC_TIMESTAMP_REQUIRED_BY_D7_VALIDATOR",
"resources": [
{
"type": "EC2_OR_ECS",
"id": "EXAMPLE_RESOURCE_ID",
"state": "terminated-or-zero-tasks"
},
{
"type": "RDS",
"id": "EXAMPLE_RESOURCE_ID",
"state": "deleted-or-approved-retained"
},
{
"type": "ECR",
"id": "EXAMPLE_REPOSITORY",
"digest": "sha256:EXAMPLE_DIGEST"
},
{
"type": "NAT_GATEWAY",
"id": "EXAMPLE_IF_CREATED",
"state": "deleted"
}
],
"budget_alarm": {
"currency": "USD",
"threshold": "EXAMPLE_LIMIT",
"notification_tested": false
},
"official_console_screenshot_sha256": "EXAMPLE_AFTER_REAL_EXTERNAL_RUN"
}
08D7 primary evidence — URL·commit·두 파일 hash의 수동 closure
illustrative/text/W22-D7-primary-evidence-contract.txt
학습용 예시 · PDF contract/template · 정본 답안 아님 · 학습용 예시 · 정본 답안 아님 · W22-F0818줄 연결18줄 번역2 chunks
D7 primary evidence — URL·commit·두 파일 hash의 수동 closure
illustrative/text/W22-D7-primary-evidence-contract.txt
학습용 예시 · PDF contract/template · 정본 답안 아님 · 학습용 예시 · 정본 답안 아님 · W22-F08STEP 01 / 13
오늘 이 코드에서 해결할 문제
무엇을 이해해야 하는지 질문부터 잡습니다.
공식 GitHub run과 screenshot·resource inventory hash, budget·teardown 상태를 같은 D7 primary evidence에 묶는 수동 계약이다.
- `official_run_url`은 어느 줄에서 생길까?
- 입력→guard→관찰→cleanup 순서는 무엇인가?
- local owner와 external human review는 누구인가?
- 직접 관찰하지 않은 Green은 무엇인가?
- 반례는 `예시 URL·0 hash는 실제 증거가 아니다`이라는 경계와 어떻게 연결되는가?
official_run_url40-hex committwo SHA-256 bindingsteardown_verifiedMANUAL_REVIEW_REQUIREDSTEP 02 / 13
아주 짧게: 이 코드는 왜 필요할까?
웹소설 대신 이 코드가 필요한 이유만 두 문단으로 쉽게 봅니다.
STARRY가 GitHub run표·AWS 출입증·DB 복구 영수증·SQL 결과표를 서로 다른 칸에 놓는다.
D7 primary evidence — URL·commit·두 파일 hash의 수동 closure ― 증거 흐름으로 바꾸기
공식 GitHub run과 screenshot·resource inventory hash, budget·teardown 상태를 같은 D7 primary evidence에 묶는 수동 계약이다.
핵심값 official_run_url, 40-hex commit, two SHA-256 bindings, teardown_verified, MANUAL_REVIEW_REQUIRED을 원본 줄로 따라가되, `예시 URL·0 hash는 실제 증거가 아니다`까지 함께 표시해 Green 범위를 부풀리지 않는다.
딱 여기까지만 비유는 owner와 순서를 기억하게 할 뿐 외부 실행·AWS 계정 상태·PostgreSQL restore·SQL 결과를 자동 증명하지 않는다.
STEP 03 / 13
초등학생도 이해하는 설명
생활 비유와 실제 코드의 경계를 함께 확인합니다.
원문 1–10줄
1~10줄을 한 덩어리로 읽어 1번째 움직임을 본다. 공식 GitHub run과 screenshot·resource inventory hash, budget·teardown 상태를 같은 D7 primary evidence에 묶는 수동 계약이다.
- 코드 연결
1~10줄- 비유
- 공식 경기 URL, 선수 번호 commit, 현장 사진과 반납 목록의 봉인 hash를 한 장의 수동 폐장 확인서에 묶는 절차
- 비유의 끝
- 예시 URL·0 hash는 실제 증거가 아니다
원문 11–18줄
11~18줄을 한 덩어리로 읽어 2번째 움직임을 본다. 공식 GitHub run과 screenshot·resource inventory hash, budget·teardown 상태를 같은 D7 primary evidence에 묶는 수동 계약이다.
- 코드 연결
11~18줄- 비유
- 공식 경기 URL, 선수 번호 commit, 현장 사진과 반납 목록의 봉인 hash를 한 장의 수동 폐장 확인서에 묶는 절차
- 비유의 끝
- 다른 날짜 evidence가 Gate를 대신하지 않는다
문제의 첫 장면
-
첫 고정값은 `official_run_url` 맞아?
-
공식 GitHub run과 screenshot·resource inventory hash, budget·teardown 상태를 같은 D7 primary evidence에 묶는 수동 계약이다.
-
원문에서 `official_run_url`이 생기는 위치를 찾자.
-
그리고 `예시 URL·0 hash는 실제 증거가 아니다`도 같이 적어.
입력에서 결과까지
-
`40-hex commit`은 언제 생겨?
-
공식 run URL과 run_id를 묶는다. → 40-hex commit과 conclusion을 확인한다.
-
screenshot·inventory 파일 hash를 재계산한다. → budget·teardown을 사람이 확인한 뒤 closure 상태를 갱신한다.
-
관찰값과 `다른 날짜 evidence가 Gate를 대신하지 않는다`을 분리하면 돼.
STEP 04 / 13
비유 ↔ 코드 전체 연결표
감사 규칙상 연결 대상인 원본 18줄을 빠짐없이 연결합니다.
| 줄 | 정확한 원본 줄 | STARRY 비유 | 실제 뜻·입력·결과·한계 |
|---|---|---|---|
| 1줄F08-L01 | 학습용 예시 · PDF 외부 primary evidence schema · 정본 답안 아님 |
공식 경기 URL, 선수 번호 commit, 현장 사진과 반납 목록의 봉인 hash를 한 장의 수동 폐장 확인서에 묶는 절차 | 수동 external primary evidence closure 계약의 1번째 원문을 앞 guard와 뒤 관찰값 사이에 연결한다.
|
| 2줄F08-L02 | execution: |
공식 경기 URL, 선수 번호 commit, 현장 사진과 반납 목록의 봉인 hash를 한 장의 수동 폐장 확인서에 묶는 절차 | 실제 외부 실행을 아직 수행·증명하지 않았다는 상태를 명시한다.
|
| 3줄F08-L03 | review_status: |
공식 경기 URL, 선수 번호 commit, 현장 사진과 반납 목록의 봉인 hash를 한 장의 수동 폐장 확인서에 묶는 절차 | 자동 shape/hash 검사 뒤에도 사람의 의미 검토가 남았음을 고정한다.
|
| 4줄F08-L04 | official_run_url: |
공식 경기 URL, 선수 번호 commit, 현장 사진과 반납 목록의 봉인 hash를 한 장의 수동 폐장 확인서에 묶는 절차 | 공식 GitHub Actions run을 가리키는 URL field를 선언한다.
|
| 5줄F08-L05 | run_id: |
공식 경기 URL, 선수 번호 commit, 현장 사진과 반납 목록의 봉인 hash를 한 장의 수동 폐장 확인서에 묶는 절차 | 수동 external primary evidence closure 계약에서 `run_id: 1234567890` field·값 또는 assignment를 다음 단계에 전달한다.
|
| 6줄F08-L06 | commit_sha: |
공식 경기 URL, 선수 번호 commit, 현장 사진과 반납 목록의 봉인 hash를 한 장의 수동 폐장 확인서에 묶는 절차 | 수동 external primary evidence closure 계약에서 `commit_sha: 000000000000000000000000000000000000` field·값 또는 assignment를 다음 단계에 전달한다.
|
| 7줄F08-L07 | workflow_name: |
공식 경기 URL, 선수 번호 commit, 현장 사진과 반납 목록의 봉인 hash를 한 장의 수동 폐장 확인서에 묶는 절차 | 수동 external primary evidence closure 계약에서 `workflow_name: example-workflow-name` field·값 또는 assignment를 다음 단계에 전달한다.
|
| 8줄F08-L08 | conclusion: |
공식 경기 URL, 선수 번호 commit, 현장 사진과 반납 목록의 봉인 hash를 한 장의 수동 폐장 확인서에 묶는 절차 | 수동 external primary evidence closure 계약에서 `conclusion: success` field·값 또는 assignment를 다음 단계에 전달한다.
|
| 9줄F08-L09 | screenshot_path: |
공식 경기 URL, 선수 번호 commit, 현장 사진과 반납 목록의 봉인 hash를 한 장의 수동 폐장 확인서에 묶는 절차 | 수동 external primary evidence closure 계약에서 `screenshot_path: evidence/w22/aws-console.png` field·값 또는 assignment를 다음 단계에 전달한다.
|
| 10줄F08-L10 | screenshot_sha256: |
공식 경기 URL, 선수 번호 commit, 현장 사진과 반납 목록의 봉인 hash를 한 장의 수동 폐장 확인서에 묶는 절차 | 현재 file bytes를 64-hex SHA-256 값과 결박하는 field 또는 검사를 다룬다.
|
| 11줄F08-L11 | resource_inventory_path: |
공식 경기 URL, 선수 번호 commit, 현장 사진과 반납 목록의 봉인 hash를 한 장의 수동 폐장 확인서에 묶는 절차 | 수동 external primary evidence closure 계약에서 `resource_inventory_path: evidence/w22/aws-resour` field·값 또는 assignment를 다음 단계에 전달한다.
|
| 12줄F08-L12 | resource_inventory_sha256: |
공식 경기 URL, 선수 번호 commit, 현장 사진과 반납 목록의 봉인 hash를 한 장의 수동 폐장 확인서에 묶는 절차 | 현재 file bytes를 64-hex SHA-256 값과 결박하는 field 또는 검사를 다룬다.
|
| 13줄F08-L13 | teardown_verified: |
공식 경기 URL, 선수 번호 commit, 현장 사진과 반납 목록의 봉인 hash를 한 장의 수동 폐장 확인서에 묶는 절차 | 수동 external primary evidence closure 계약에서 `teardown_verified: false` field·값 또는 assignment를 다음 단계에 전달한다.
|
| 14줄F08-L14 | budget_alarm_verified: |
공식 경기 URL, 선수 번호 commit, 현장 사진과 반납 목록의 봉인 hash를 한 장의 수동 폐장 확인서에 묶는 절차 | resource 생성 전 비용 경계와 알림 상태를 기록한다.
|
| 15줄F08-L15 | retained_resources: |
공식 경기 URL, 선수 번호 commit, 현장 사진과 반납 목록의 봉인 hash를 한 장의 수동 폐장 확인서에 묶는 절차 | 수동 external primary evidence closure 계약에서 `retained_resources: EXAMPLE_NONE_OR_ID_REASON_EX` field·값 또는 assignment를 다음 단계에 전달한다.
|
| 16줄F08-L16 | closure_marker: |
공식 경기 URL, 선수 번호 commit, 현장 사진과 반납 목록의 봉인 hash를 한 장의 수동 폐장 확인서에 묶는 절차 | 자동 shape/hash 검사 뒤에도 사람의 의미 검토가 남았음을 고정한다.
|
| 17줄F08-L17 | boundary: |
공식 경기 URL, 선수 번호 commit, 현장 사진과 반납 목록의 봉인 hash를 한 장의 수동 폐장 확인서에 묶는 절차 | 수동 external primary evidence closure 계약에서 `boundary: 실제 URL·commit·두 파일 hash·teardown·budge` field·값 또는 assignment를 다음 단계에 전달한다.
|
| 18줄F08-L18 | precedessor_rule: |
공식 경기 URL, 선수 번호 commit, 현장 사진과 반납 목록의 봉인 hash를 한 장의 수동 폐장 확인서에 묶는 절차 | 수동 external primary evidence closure 계약에서 `precedessor_rule: 이전 주 index 또는 다른 날짜 evidence는 ` field·값 또는 assignment를 다음 단계에 전달한다.
|
Green 범위
-
marker나 파일이 보이면 전부 성공이야?
-
아니. source가 직접 검증한 범위만 말해야 해.
-
직접 연결되는 대표 값은 `MANUAL_REVIEW_REQUIRED`이야.
-
`predecessor index 성공은 D7 성공이 아니다`는 별도 증거가 필요해.
STEP 05 / 13
원본 코드 조각
원본을 2개 의미 조각으로 나누어 그대로 확인합니다.
파일을 한꺼번에 외우지 않고 실행 의미가 이어지는 작은 조각으로 봅니다. 아래 코드는 prompt·fixture·가정을 밝힌 학습용 예시 source이며, 제공 정본 답안이 아닙니다.
학습용 예시 · PDF 외부 primary evidence schema · 정본 답안 아님
execution: NOT_RUN_EXTERNAL
review_status: MANUAL_REVIEW_REQUIRED
official_run_url: https://github.com/example-owner/example-repo/actions/runs/1234567890
run_id: 1234567890
commit_sha: 0000000000000000000000000000000000000000
workflow_name: example-workflow-name
conclusion: success
screenshot_path: evidence/w22/aws-console.png
screenshot_sha256: 0000000000000000000000000000000000000000000000000000000000000000
resource_inventory_path: evidence/w22/aws-resource-inventory.json
resource_inventory_sha256: 0000000000000000000000000000000000000000000000000000000000000000
teardown_verified: false
budget_alarm_verified: false
retained_resources: EXAMPLE_NONE_OR_ID_REASON_EXPIRY
closure_marker: W22D7_PRIMARY_EVIDENCE_MANUAL_REVIEW_REQUIRED
boundary: 실제 URL·commit·두 파일 hash·teardown·budget을 사람이 대조하기 전 Green이 아니다.
precedessor_rule: 이전 주 index 또는 다른 날짜 evidence는 이 Gate를 대신할 수 없다.
STEP 06 / 13
코드 한 줄씩 한국어로 번역
비어 있지 않은 18줄을 모두 한국어로 옮깁니다.
비어 있지 않은 원본 줄은 하나도 생략하지 않습니다.
| 줄 | 원본 | 한국어 번역 |
|---|---|---|
| 1 | 학습용 예시 · PDF 외부 primary evidence schema · 정본 답안 아님 | 수동 external primary evidence closure 계약의 1번째 원문을 앞 guard와 뒤 관찰값 사이에 연결한다. |
| 2 | execution: NOT_RUN_EXTERNAL | 실제 외부 실행을 아직 수행·증명하지 않았다는 상태를 명시한다. |
| 3 | review_status: MANUAL_REVIEW_REQUIRED | 자동 shape/hash 검사 뒤에도 사람의 의미 검토가 남았음을 고정한다. |
| 4 | official_run_url: https://github.com/example-owner/example-repo/actions/runs/1234567890 | 공식 GitHub Actions run을 가리키는 URL field를 선언한다. |
| 5 | run_id: 1234567890 | 수동 external primary evidence closure 계약에서 `run_id: 1234567890` field·값 또는 assignment를 다음 단계에 전달한다. |
| 6 | commit_sha: 0000000000000000000000000000000000000000 | 수동 external primary evidence closure 계약에서 `commit_sha: 000000000000000000000000000000000000` field·값 또는 assignment를 다음 단계에 전달한다. |
| 7 | workflow_name: example-workflow-name | 수동 external primary evidence closure 계약에서 `workflow_name: example-workflow-name` field·값 또는 assignment를 다음 단계에 전달한다. |
| 8 | conclusion: success | 수동 external primary evidence closure 계약에서 `conclusion: success` field·값 또는 assignment를 다음 단계에 전달한다. |
| 9 | screenshot_path: evidence/w22/aws-console.png | 수동 external primary evidence closure 계약에서 `screenshot_path: evidence/w22/aws-console.png` field·값 또는 assignment를 다음 단계에 전달한다. |
| 10 | screenshot_sha256: 0000000000000000000000000000000000000000000000000000000000000000 | 현재 file bytes를 64-hex SHA-256 값과 결박하는 field 또는 검사를 다룬다. |
| 11 | resource_inventory_path: evidence/w22/aws-resource-inventory.json | 수동 external primary evidence closure 계약에서 `resource_inventory_path: evidence/w22/aws-resour` field·값 또는 assignment를 다음 단계에 전달한다. |
| 12 | resource_inventory_sha256: 0000000000000000000000000000000000000000000000000000000000000000 | 현재 file bytes를 64-hex SHA-256 값과 결박하는 field 또는 검사를 다룬다. |
| 13 | teardown_verified: false | 수동 external primary evidence closure 계약에서 `teardown_verified: false` field·값 또는 assignment를 다음 단계에 전달한다. |
| 14 | budget_alarm_verified: false | resource 생성 전 비용 경계와 알림 상태를 기록한다. |
| 15 | retained_resources: EXAMPLE_NONE_OR_ID_REASON_EXPIRY | 수동 external primary evidence closure 계약에서 `retained_resources: EXAMPLE_NONE_OR_ID_REASON_EX` field·값 또는 assignment를 다음 단계에 전달한다. |
| 16 | closure_marker: W22D7_PRIMARY_EVIDENCE_MANUAL_REVIEW_REQUIRED | 자동 shape/hash 검사 뒤에도 사람의 의미 검토가 남았음을 고정한다. |
| 17 | boundary: 실제 URL·commit·두 파일 hash·teardown·budget을 사람이 대조하기 전 Green이 아니다. | 수동 external primary evidence closure 계약에서 `boundary: 실제 URL·commit·두 파일 hash·teardown·budge` field·값 또는 assignment를 다음 단계에 전달한다. |
| 18 | precedessor_rule: 이전 주 index 또는 다른 날짜 evidence는 이 Gate를 대신할 수 없다. | 수동 external primary evidence closure 계약에서 `precedessor_rule: 이전 주 index 또는 다른 날짜 evidence는 ` field·값 또는 assignment를 다음 단계에 전달한다. |
STEP 07 / 13
기존 수준의 한 줄 읽기·문법 해부
쉬운 설명 다음에 문법과 실행 순서를 정밀하게 읽습니다.
한 줄로 읽기공식 GitHub run과 screenshot·resource inventory hash, budget·teardown 상태를 같은 D7 primary evidence에 묶는 수동 계약이다. 다만 예시 URL·0 hash는 실제 증거가 아니다
문법 해부
- field 이름과 값은 D7 validator가 찾는 exact evidence schema를 나타낸다.
- example URL·0 hash·false control은 실제값이 아니라 미실행을 드러내는 비정본 표식이다.
실행 순서
- 공식 run URL과 run_id를 묶는다.
- 40-hex commit과 conclusion을 확인한다.
- screenshot·inventory 파일 hash를 재계산한다.
- budget·teardown을 사람이 확인한 뒤 closure 상태를 갱신한다.
W22 조각별 정밀 해설
F08-C01 · 원문 1–10줄
- 문법 해부
- 1~10줄의 `원문 1–10줄`을 입력·guard·관찰·cleanup 단계로 나눈다.
- 실제 값 추적
- 항목 전체 흐름에 연결해 `official_run_url`을 대조한다. 이 값이 chunk 단독 산출이라는 뜻은 아니다.
- 정상 예
- 정상 예에서는 source 순서와 owner 계약이 일치해 `official_run_url`을 관찰한다.
- 틀린 예·반례
- 반례에서는 선행 guard·stable order·cleanup을 생략한다. 동결 경계: 예시 URL·0 hash는 실제 증거가 아니다.
- 착각 방지
- `원문 1–10줄`이 항목 전체 Green을 단독 증명한다고 읽지 않는다.
- 하지 않는 일
- 이 chunk가 책임지지 않는 범위: 예시 URL·0 hash는 실제 증거가 아니다.
- 다음 연결
- 다음 source chunk의 입력 또는 최종 marker/SQL oracle로 결과를 넘긴다.
F08-C02 · 원문 11–18줄
- 문법 해부
- 11~18줄의 `원문 11–18줄`을 입력·guard·관찰·cleanup 단계로 나눈다.
- 실제 값 추적
- 항목 전체 흐름에 연결해 `40-hex commit`을 대조한다. 이 값이 chunk 단독 산출이라는 뜻은 아니다.
- 정상 예
- 정상 예에서는 source 순서와 owner 계약이 일치해 `40-hex commit`을 관찰한다.
- 틀린 예·반례
- 반례에서는 선행 guard·stable order·cleanup을 생략한다. 동결 경계: 다른 날짜 evidence가 Gate를 대신하지 않는다.
- 착각 방지
- `원문 11–18줄`이 항목 전체 Green을 단독 증명한다고 읽지 않는다.
- 하지 않는 일
- 이 chunk가 책임지지 않는 범위: 다른 날짜 evidence가 Gate를 대신하지 않는다.
- 다음 연결
- 다음 source chunk의 입력 또는 최종 marker/SQL oracle로 결과를 넘긴다.
반례
-
겉보기에는 맞지만 깨지는 예는?
-
예시 URL과 0 hash를 실제 증거로 둔다
-
그 상태는 owner·입력·관찰 중 한 칸이 비어 있어.
-
수정한 뒤 같은 source와 hash로 다시 대조해.
STEP 08 / 13
실제 값 따라가기
같은 입력값이 어느 줄을 지나 어떤 결과가 되는지 추적합니다.
| 순서 | 들어온 값 | 코드가 하는 일 | 나온 값·상태 | 경계 |
|---|---|---|---|---|
| F08-T01 run | official URL | numeric id match | bound run | example URL은 무효 |
| F08-T02 files | two learner files | SHA-256 | exact bindings | 경로 존재도 필요 |
| F08-T03 controls | budget+teardown | manual review | primary marker | predecessor가 대신 못함 |
책임 경계
-
이 항목의 마지막 책임선은?
-
직접 역할은 `수동 external primary evidence closure 계약`이야.
-
대표 경계는 `사람 의미 검토 전 Green이 아니다`이야.
-
정본/비정본 label과 evidence owner까지 확인하면 끝이야.
STEP 09 / 13
GitHub·AWS·PowerShell·PostgreSQL 내부에서 벌어지는 일
GitHub·AWS·PowerShell·PostgreSQL에서 실제로 일어나는 일과 증명 범위를 구분합니다.
URL/run ID와 40-hex commit shape를 검사한다.
형식 검사는 source 의미를 보장하지 않는다.현재 두 파일 byte를 evidence field와 비교한다.
screenshot 내용은 사람이 읽는다.PRIMARY_PRODUCER=0인 manual external Gate다.
다른 주 restore-result가 aws-gate를 대신하지 않는다.STEP 10 / 13
흔한 착각과 틀린 예
그럴듯하지만 틀린 해석을 반례로 고칩니다.
❌ 예시 URL과 0 hash를 실제 증거로 둔다
왜 틀리나 수동 external primary evidence closure 계약의 owner·관찰·경계 중 적어도 하나를 건너뛴다.
바르게 읽기 공식 run URL과 run_id를 묶는다. 그리고 source의 실제 값과 hash를 다시 대조한다.
반례 반례에서는 `예시 URL·0 hash는 실제 증거가 아니다` 상태인데도 Green을 주장하게 된다.
❌ run URL의 numeric id와 run_id가 다르다
왜 틀리나 수동 external primary evidence closure 계약의 owner·관찰·경계 중 적어도 하나를 건너뛴다.
바르게 읽기 40-hex commit과 conclusion을 확인한다. 그리고 source의 실제 값과 hash를 다시 대조한다.
반례 반례에서는 `다른 날짜 evidence가 Gate를 대신하지 않는다` 상태인데도 Green을 주장하게 된다.
❌ screenshot만 있고 inventory 파일이 없다
왜 틀리나 수동 external primary evidence closure 계약의 owner·관찰·경계 중 적어도 하나를 건너뛴다.
바르게 읽기 screenshot·inventory 파일 hash를 재계산한다. 그리고 source의 실제 값과 hash를 다시 대조한다.
반례 반례에서는 `predecessor index 성공은 D7 성공이 아니다` 상태인데도 Green을 주장하게 된다.
❌ budget·teardown false인데 success라 쓴다
왜 틀리나 수동 external primary evidence closure 계약의 owner·관찰·경계 중 적어도 하나를 건너뛴다.
바르게 읽기 budget·teardown을 사람이 확인한 뒤 closure 상태를 갱신한다. 그리고 source의 실제 값과 hash를 다시 대조한다.
반례 반례에서는 `사람 의미 검토 전 Green이 아니다` 상태인데도 Green을 주장하게 된다.
❌ predecessor index 성공으로 D7을 대체한다
왜 틀리나 수동 external primary evidence closure 계약의 owner·관찰·경계 중 적어도 하나를 건너뛴다.
바르게 읽기 budget·teardown을 사람이 확인한 뒤 closure 상태를 갱신한다. 그리고 source의 실제 값과 hash를 다시 대조한다.
반례 반례에서는 `예시 URL·0 hash는 실제 증거가 아니다` 상태인데도 Green을 주장하게 된다.
STEP 11 / 13
이 코드가 보장하지 않는 것
이 코드가 책임지지 않는 일을 분리합니다.
예시 URL·0 hash는 실제 증거가 아니다
이 책임을 맡는 곳: 별도 외부/selector 실행다른 날짜 evidence가 Gate를 대신하지 않는다
이 책임을 맡는 곳: secret·운영 정책predecessor index 성공은 D7 성공이 아니다
이 책임을 맡는 곳: infrastructure·사람 검토사람 의미 검토 전 Green이 아니다
이 책임을 맡는 곳: owner lifecycleSTEP 12 / 13
직접 다시 써보기
뜻 → 조각 → 전체 코드 순서로 다시 씁니다.
1단계 · 뜻부터 복원
다음 역할을 고정값과 미보장 경계까지 말한다: 공식 GitHub run과 screenshot·resource inventory hash, budget·teardown 상태를 같은 D7 primary evidence에 묶는 수동 계약이다.
2단계 · 코드 조각 재조립
- 원문 1–10줄
- 원문 11–18줄
3단계 · 파일 전체 다시 쓰기
18개 물리 줄을 원본 순서로 복원하고 SHA-256 5177fe33fb2445565eccaf1060eaf440ac8516fb82d331ea0b6e0ef2ff20bc6b와 대조한다.
자가 점검
- 원본 source/template bytes를 바꾸지 않았는가?
- 외부 미실행과 local restore Green을 구분했는가?
- secret 원문을 evidence에 남기지 않았는가?
- D7 checked_at 충돌과 사람 검토 경계를 보았는가?
- Q35/Q36을 workbook 정본 답안이라고 부르지 않았는가?
STEP 13 / 13
전체 원본 source
감사로 고정한 전체 source를 가감 없이 확인합니다.
학습용 예시 전체 확인하기 · 정본 답안 아님
학습용 예시 · PDF 외부 primary evidence schema · 정본 답안 아님
execution: NOT_RUN_EXTERNAL
review_status: MANUAL_REVIEW_REQUIRED
official_run_url: https://github.com/example-owner/example-repo/actions/runs/1234567890
run_id: 1234567890
commit_sha: 0000000000000000000000000000000000000000
workflow_name: example-workflow-name
conclusion: success
screenshot_path: evidence/w22/aws-console.png
screenshot_sha256: 0000000000000000000000000000000000000000000000000000000000000000
resource_inventory_path: evidence/w22/aws-resource-inventory.json
resource_inventory_sha256: 0000000000000000000000000000000000000000000000000000000000000000
teardown_verified: false
budget_alarm_verified: false
retained_resources: EXAMPLE_NONE_OR_ID_REASON_EXPIRY
closure_marker: W22D7_PRIMARY_EVIDENCE_MANUAL_REVIEW_REQUIRED
boundary: 실제 URL·commit·두 파일 hash·teardown·budget을 사람이 대조하기 전 Green이 아니다.
precedessor_rule: 이전 주 index 또는 다른 날짜 evidence는 이 Gate를 대신할 수 없다.
09W22-SQL-Q35 — 날짜별 선집계 뒤 calendar 7일 RANGE
illustrative/sql/W22-SQL-Q35.sql
학습용 예시 · 정본 답안 아님 · 학습용 예시 · 정본 답안 아님 · W22-F0925줄 연결25줄 번역3 chunks
W22-SQL-Q35 — 날짜별 선집계 뒤 calendar 7일 RANGE
illustrative/sql/W22-SQL-Q35.sql
학습용 예시 · 정본 답안 아님 · 학습용 예시 · 정본 답안 아님 · W22-F09STEP 01 / 13
오늘 이 코드에서 해결할 문제
무엇을 이해해야 하는지 질문부터 잡습니다.
business_date별 합계를 먼저 만들고 calendar 7일 범위를 RANGE window frame으로 계산하는 비정본 Q35 예시다.
- `daily grain`은 어느 줄에서 생길까?
- 입력→guard→관찰→cleanup 순서는 무엇인가?
- local owner와 external human review는 누구인가?
- 직접 관찰하지 않은 Green은 무엇인가?
- 반례는 `workbook 제공 정답이 아니다`이라는 경계와 어떻게 연결되는가?
daily grainRANGE 6 days precedingfixture rows=92027-01-02 daily=4200moving=1205002STEP 02 / 13
아주 짧게: 이 코드는 왜 필요할까?
웹소설 대신 이 코드가 필요한 이유만 두 문단으로 쉽게 봅니다.
STARRY가 GitHub run표·AWS 출입증·DB 복구 영수증·SQL 결과표를 서로 다른 칸에 놓는다.
W22-SQL-Q35 — 날짜별 선집계 뒤 calendar 7일 RANGE ― 증거 흐름으로 바꾸기
business_date별 합계를 먼저 만들고 calendar 7일 범위를 RANGE window frame으로 계산하는 비정본 Q35 예시다.
핵심값 daily grain, RANGE 6 days preceding, fixture rows=9, 2027-01-02 daily=4200, moving=1205002을 원본 줄로 따라가되, `workbook 제공 정답이 아니다`까지 함께 표시해 Green 범위를 부풀리지 않는다.
딱 여기까지만 비유는 owner와 순서를 기억하게 할 뿐 외부 실행·AWS 계정 상태·PostgreSQL restore·SQL 결과를 자동 증명하지 않는다.
STEP 03 / 13
초등학생도 이해하는 설명
생활 비유와 실제 코드의 경계를 함께 확인합니다.
원문 1–10줄
1~10줄을 한 덩어리로 읽어 1번째 움직임을 본다. business_date별 합계를 먼저 만들고 calendar 7일 범위를 RANGE window frame으로 계산하는 비정본 Q35 예시다.
- 코드 연결
1~10줄- 비유
- 날짜별 영수증을 먼저 한 장으로 합친 뒤, 오늘을 포함한 최근 7칸의 달력 범위만 투명 자로 덮어 더하는 표
- 비유의 끝
- workbook 제공 정답이 아니다
원문 11–20줄
11~20줄을 한 덩어리로 읽어 2번째 움직임을 본다. business_date별 합계를 먼저 만들고 calendar 7일 범위를 RANGE window frame으로 계산하는 비정본 Q35 예시다.
- 코드 연결
11~20줄- 비유
- 날짜별 영수증을 먼저 한 장으로 합친 뒤, 오늘을 포함한 최근 7칸의 달력 범위만 투명 자로 덮어 더하는 표
- 비유의 끝
- 모든 status 포함은 명시한 학습 가정이다
원문 21–27줄
21~27줄을 한 덩어리로 읽어 3번째 움직임을 본다. business_date별 합계를 먼저 만들고 calendar 7일 범위를 RANGE window frame으로 계산하는 비정본 Q35 예시다.
- 코드 연결
21~27줄- 비유
- 날짜별 영수증을 먼저 한 장으로 합친 뒤, 오늘을 포함한 최근 7칸의 달력 범위만 투명 자로 덮어 더하는 표
- 비유의 끝
- 누락일 자체를 0행으로 생성하지 않는다
문제의 첫 장면
-
첫 고정값은 `daily grain` 맞아?
-
business_date별 합계를 먼저 만들고 calendar 7일 범위를 RANGE window frame으로 계산하는 비정본 Q35 예시다.
-
원문에서 `daily grain`이 생기는 위치를 찾자.
-
그리고 `workbook 제공 정답이 아니다`도 같이 적어.
입력에서 결과까지
-
`RANGE 6 days preceding`은 언제 생겨?
-
business_tx를 날짜별 SUM한다. → 한 날짜 한 행을 만든다.
-
calendar range window를 적용한다. → 누락일·ROWS 반례와 fixture oracle을 대조한다.
-
관찰값과 `모든 status 포함은 명시한 학습 가정이다`을 분리하면 돼.
STEP 04 / 13
비유 ↔ 코드 전체 연결표
감사 규칙상 연결 대상인 원본 25줄을 빠짐없이 연결합니다.
| 줄 | 정확한 원본 줄 | STARRY 비유 | 실제 뜻·입력·결과·한계 |
|---|---|---|---|
| 1줄F09-L01 | -- 학습용 예시 · 정본 답안 아님: |
날짜별 영수증을 먼저 한 장으로 합친 뒤, 오늘을 포함한 최근 7칸의 달력 범위만 투명 자로 덮어 더하는 표 | 이 source의 비정본 provenance, 가정, 반례, 또는 실행 경계를 사람이 확인할 주석이다.
|
| 2줄F09-L02 | -- 입력 grain: |
날짜별 영수증을 먼저 한 장으로 합친 뒤, 오늘을 포함한 최근 7칸의 달력 범위만 투명 자로 덮어 더하는 표 | 이 source의 비정본 provenance, 가정, 반례, 또는 실행 경계를 사람이 확인할 주석이다.
|
| 3줄F09-L03 | -- 학습 가정: |
날짜별 영수증을 먼저 한 장으로 합친 뒤, 오늘을 포함한 최근 7칸의 달력 범위만 투명 자로 덮어 더하는 표 | 이 source의 비정본 provenance, 가정, 반례, 또는 실행 경계를 사람이 확인할 주석이다.
|
| 4줄F09-L04 | -- 핵심 반례: |
날짜별 영수증을 먼저 한 장으로 합친 뒤, 오늘을 포함한 최근 7칸의 달력 범위만 투명 자로 덮어 더하는 표 | 이 source의 비정본 provenance, 가정, 반례, 또는 실행 경계를 사람이 확인할 주석이다.
|
| 5줄F09-L05 | SET search_path TO workbook_schema, |
날짜별 영수증을 먼저 한 장으로 합친 뒤, 오늘을 포함한 최근 7칸의 달력 범위만 투명 자로 덮어 더하는 표 | 비정본 calendar-window SQL 예시의 5번째 원문을 앞 guard와 뒤 관찰값 사이에 연결한다.
|
| 7줄F09-L07 | WITH daily AS ( |
날짜별 영수증을 먼저 한 장으로 합친 뒤, 오늘을 포함한 최근 7칸의 달력 범위만 투명 자로 덮어 더하는 표 | 날짜별 합계를 만드는 daily CTE를 연다.
|
| 8줄F09-L08 | SELECT |
날짜별 영수증을 먼저 한 장으로 합친 뒤, 오늘을 포함한 최근 7칸의 달력 범위만 투명 자로 덮어 더하는 표 | SQL의 입력 grain·필터·집계·stable 출력 순서를 구성하는 절이다.
|
| 9줄F09-L09 | business_date, |
날짜별 영수증을 먼저 한 장으로 합친 뒤, 오늘을 포함한 최근 7칸의 달력 범위만 투명 자로 덮어 더하는 표 | 비정본 calendar-window SQL 예시의 9번째 원문을 앞 guard와 뒤 관찰값 사이에 연결한다.
|
| 10줄F09-L10 | SUM( |
날짜별 영수증을 먼저 한 장으로 합친 뒤, 오늘을 포함한 최근 7칸의 달력 범위만 투명 자로 덮어 더하는 표 | 같은 business_date의 거래 amount를 하루 합계로 줄인다.
|
| 11줄F09-L11 | FROM business_tx |
날짜별 영수증을 먼저 한 장으로 합친 뒤, 오늘을 포함한 최근 7칸의 달력 범위만 투명 자로 덮어 더하는 표 | SQL의 입력 grain·필터·집계·stable 출력 순서를 구성하는 절이다.
|
| 12줄F09-L12 | GROUP BY business_date |
날짜별 영수증을 먼저 한 장으로 합친 뒤, 오늘을 포함한 최근 7칸의 달력 범위만 투명 자로 덮어 더하는 표 | SQL의 입력 grain·필터·집계·stable 출력 순서를 구성하는 절이다.
|
| 13줄F09-L13 | ) |
날짜별 영수증을 먼저 한 장으로 합친 뒤, 오늘을 포함한 최근 7칸의 달력 범위만 투명 자로 덮어 더하는 표 | 현재 object·array·block 또는 query 범위를 열거나 닫아 구조를 유지한다.
|
| 14줄F09-L14 | SELECT |
날짜별 영수증을 먼저 한 장으로 합친 뒤, 오늘을 포함한 최근 7칸의 달력 범위만 투명 자로 덮어 더하는 표 | SQL의 입력 grain·필터·집계·stable 출력 순서를 구성하는 절이다.
|
| 15줄F09-L15 | business_date, |
날짜별 영수증을 먼저 한 장으로 합친 뒤, 오늘을 포함한 최근 7칸의 달력 범위만 투명 자로 덮어 더하는 표 | 비정본 calendar-window SQL 예시의 15번째 원문을 앞 guard와 뒤 관찰값 사이에 연결한다.
|
| 16줄F09-L16 | daily_amount, |
날짜별 영수증을 먼저 한 장으로 합친 뒤, 오늘을 포함한 최근 7칸의 달력 범위만 투명 자로 덮어 더하는 표 | 비정본 calendar-window SQL 예시의 16번째 원문을 앞 guard와 뒤 관찰값 사이에 연결한다.
|
| 17줄F09-L17 | SUM( |
날짜별 영수증을 먼저 한 장으로 합친 뒤, 오늘을 포함한 최근 7칸의 달력 범위만 투명 자로 덮어 더하는 표 | 비정본 calendar-window SQL 예시의 17번째 원문을 앞 guard와 뒤 관찰값 사이에 연결한다.
|
| 18줄F09-L18 | ORDER BY business_date: |
날짜별 영수증을 먼저 한 장으로 합친 뒤, 오늘을 포함한 최근 7칸의 달력 범위만 투명 자로 덮어 더하는 표 | SQL의 입력 grain·필터·집계·stable 출력 순서를 구성하는 절이다.
|
| 19줄F09-L19 | RANGE BETWEEN INTERVAL '6 days' PRECEDING AND CURRENT ROW |
날짜별 영수증을 먼저 한 장으로 합친 뒤, 오늘을 포함한 최근 7칸의 달력 범위만 투명 자로 덮어 더하는 표 | 현재 날짜를 포함한 앞 6일, 즉 7 calendar days window frame을 지정한다.
|
| 20줄F09-L20 | ) AS moving_7_calendar_days |
날짜별 영수증을 먼저 한 장으로 합친 뒤, 오늘을 포함한 최근 7칸의 달력 범위만 투명 자로 덮어 더하는 표 | 비정본 calendar-window SQL 예시의 20번째 원문을 앞 guard와 뒤 관찰값 사이에 연결한다.
|
| 21줄F09-L21 | FROM daily |
날짜별 영수증을 먼저 한 장으로 합친 뒤, 오늘을 포함한 최근 7칸의 달력 범위만 투명 자로 덮어 더하는 표 | SQL의 입력 grain·필터·집계·stable 출력 순서를 구성하는 절이다.
|
| 22줄F09-L22 | ORDER BY business_date; |
날짜별 영수증을 먼저 한 장으로 합친 뒤, 오늘을 포함한 최근 7칸의 달력 범위만 투명 자로 덮어 더하는 표 | SQL의 입력 grain·필터·집계·stable 출력 순서를 구성하는 절이다.
|
| 24줄F09-L24 | -- fixture oracle: |
날짜별 영수증을 먼저 한 장으로 합친 뒤, 오늘을 포함한 최근 7칸의 달력 범위만 투명 자로 덮어 더하는 표 | 이 source의 비정본 provenance, 가정, 반례, 또는 실행 경계를 사람이 확인할 주석이다.
|
| 25줄F09-L25 | -- fixture oracle: |
날짜별 영수증을 먼저 한 장으로 합친 뒤, 오늘을 포함한 최근 7칸의 달력 범위만 투명 자로 덮어 더하는 표 | 이 source의 비정본 provenance, 가정, 반례, 또는 실행 경계를 사람이 확인할 주석이다.
|
| 26줄F09-L26 | -- fixture oracle: |
날짜별 영수증을 먼저 한 장으로 합친 뒤, 오늘을 포함한 최근 7칸의 달력 범위만 투명 자로 덮어 더하는 표 | 이 source의 비정본 provenance, 가정, 반례, 또는 실행 경계를 사람이 확인할 주석이다.
|
| 27줄F09-L27 | -- 누락일도 0행으로 출력해야 한다면 generate_series 달력과 LEFT JOIN을 추가해야 한다. |
날짜별 영수증을 먼저 한 장으로 합친 뒤, 오늘을 포함한 최근 7칸의 달력 범위만 투명 자로 덮어 더하는 표 | 이 source의 비정본 provenance, 가정, 반례, 또는 실행 경계를 사람이 확인할 주석이다.
|
Green 범위
-
marker나 파일이 보이면 전부 성공이야?
-
아니. source가 직접 검증한 범위만 말해야 해.
-
직접 연결되는 대표 값은 `moving=1205002`이야.
-
`누락일 자체를 0행으로 생성하지 않는다`는 별도 증거가 필요해.
STEP 05 / 13
원본 코드 조각
원본을 3개 의미 조각으로 나누어 그대로 확인합니다.
파일을 한꺼번에 외우지 않고 실행 의미가 이어지는 작은 조각으로 봅니다. 아래 코드는 prompt·fixture·가정을 밝힌 학습용 예시 source이며, 제공 정본 답안이 아닙니다.
-- 학습용 예시 · 정본 답안 아님: workbook은 W22-SQL-Q35 답안을 제공하지 않는다.
-- 입력 grain: business_tx 한 행 = 거래 한 건. 출력 grain: business_date 한 행 = 그 날짜의 합계와 7일 이동합계.
-- 학습 가정: prompt에 status filter가 없으므로 SUCCESS·FAILED·UNKNOWN·PROCESSING을 모두 포함한다.
-- 핵심 반례: 누락일이 많아도 ROWS 6 PRECEDING은 최근 7개 '행'을 세므로 7개 달력일과 다르다.
SET search_path TO workbook_schema, public;
WITH daily AS (
SELECT
business_date,
SUM(amount) AS daily_amount
FROM business_tx
GROUP BY business_date
)
SELECT
business_date,
daily_amount,
SUM(daily_amount) OVER (
ORDER BY business_date::timestamp
RANGE BETWEEN INTERVAL '6 days' PRECEDING AND CURRENT ROW
) AS moving_7_calendar_days
FROM daily
ORDER BY business_date;
-- fixture oracle: 9행. 2026-06-30=2129999, 2026-07-01 이동합계=2132199.
-- fixture oracle: 긴 누락 뒤 2026-12-28 이동합계는 303으로 다시 시작한다.
-- fixture oracle: 2027-01-02 daily_amount=4200, moving_7_calendar_days=1205002.
-- 누락일도 0행으로 출력해야 한다면 generate_series 달력과 LEFT JOIN을 추가해야 한다.
STEP 06 / 13
코드 한 줄씩 한국어로 번역
비어 있지 않은 25줄을 모두 한국어로 옮깁니다.
비어 있지 않은 원본 줄은 하나도 생략하지 않습니다.
| 줄 | 원본 | 한국어 번역 |
|---|---|---|
| 1 | -- 학습용 예시 · 정본 답안 아님: workbook은 W22-SQL-Q35 답안을 제공하지 않는다. | 이 source의 비정본 provenance, 가정, 반례, 또는 실행 경계를 사람이 확인할 주석이다. |
| 2 | -- 입력 grain: business_tx 한 행 = 거래 한 건. 출력 grain: business_date 한 행 = 그 날짜의 합계와 7일 이동합계. | 이 source의 비정본 provenance, 가정, 반례, 또는 실행 경계를 사람이 확인할 주석이다. |
| 3 | -- 학습 가정: prompt에 status filter가 없으므로 SUCCESS·FAILED·UNKNOWN·PROCESSING을 모두 포함한다. | 이 source의 비정본 provenance, 가정, 반례, 또는 실행 경계를 사람이 확인할 주석이다. |
| 4 | -- 핵심 반례: 누락일이 많아도 ROWS 6 PRECEDING은 최근 7개 '행'을 세므로 7개 달력일과 다르다. | 이 source의 비정본 provenance, 가정, 반례, 또는 실행 경계를 사람이 확인할 주석이다. |
| 5 | SET search_path TO workbook_schema, public; | 비정본 calendar-window SQL 예시의 5번째 원문을 앞 guard와 뒤 관찰값 사이에 연결한다. |
| 7 | WITH daily AS ( | 날짜별 합계를 만드는 daily CTE를 연다. |
| 8 | SELECT | SQL의 입력 grain·필터·집계·stable 출력 순서를 구성하는 절이다. |
| 9 | business_date, | 비정본 calendar-window SQL 예시의 9번째 원문을 앞 guard와 뒤 관찰값 사이에 연결한다. |
| 10 | SUM(amount) AS daily_amount | 같은 business_date의 거래 amount를 하루 합계로 줄인다. |
| 11 | FROM business_tx | SQL의 입력 grain·필터·집계·stable 출력 순서를 구성하는 절이다. |
| 12 | GROUP BY business_date | SQL의 입력 grain·필터·집계·stable 출력 순서를 구성하는 절이다. |
| 13 | ) | 현재 object·array·block 또는 query 범위를 열거나 닫아 구조를 유지한다. |
| 14 | SELECT | SQL의 입력 grain·필터·집계·stable 출력 순서를 구성하는 절이다. |
| 15 | business_date, | 비정본 calendar-window SQL 예시의 15번째 원문을 앞 guard와 뒤 관찰값 사이에 연결한다. |
| 16 | daily_amount, | 비정본 calendar-window SQL 예시의 16번째 원문을 앞 guard와 뒤 관찰값 사이에 연결한다. |
| 17 | SUM(daily_amount) OVER ( | 비정본 calendar-window SQL 예시의 17번째 원문을 앞 guard와 뒤 관찰값 사이에 연결한다. |
| 18 | ORDER BY business_date::timestamp | SQL의 입력 grain·필터·집계·stable 출력 순서를 구성하는 절이다. |
| 19 | RANGE BETWEEN INTERVAL '6 days' PRECEDING AND CURRENT ROW | 현재 날짜를 포함한 앞 6일, 즉 7 calendar days window frame을 지정한다. |
| 20 | ) AS moving_7_calendar_days | 비정본 calendar-window SQL 예시의 20번째 원문을 앞 guard와 뒤 관찰값 사이에 연결한다. |
| 21 | FROM daily | SQL의 입력 grain·필터·집계·stable 출력 순서를 구성하는 절이다. |
| 22 | ORDER BY business_date; | SQL의 입력 grain·필터·집계·stable 출력 순서를 구성하는 절이다. |
| 24 | -- fixture oracle: 9행. 2026-06-30=2129999, 2026-07-01 이동합계=2132199. | 이 source의 비정본 provenance, 가정, 반례, 또는 실행 경계를 사람이 확인할 주석이다. |
| 25 | -- fixture oracle: 긴 누락 뒤 2026-12-28 이동합계는 303으로 다시 시작한다. | 이 source의 비정본 provenance, 가정, 반례, 또는 실행 경계를 사람이 확인할 주석이다. |
| 26 | -- fixture oracle: 2027-01-02 daily_amount=4200, moving_7_calendar_days=1205002. | 이 source의 비정본 provenance, 가정, 반례, 또는 실행 경계를 사람이 확인할 주석이다. |
| 27 | -- 누락일도 0행으로 출력해야 한다면 generate_series 달력과 LEFT JOIN을 추가해야 한다. | 이 source의 비정본 provenance, 가정, 반례, 또는 실행 경계를 사람이 확인할 주석이다. |
STEP 07 / 13
기존 수준의 한 줄 읽기·문법 해부
쉬운 설명 다음에 문법과 실행 순서를 정밀하게 읽습니다.
한 줄로 읽기business_date별 합계를 먼저 만들고 calendar 7일 범위를 RANGE window frame으로 계산하는 비정본 Q35 예시다. 다만 workbook 제공 정답이 아니다
문법 해부
- CTE `daily`가 거래 grain을 날짜 grain으로 먼저 줄인다.
- timestamp ORDER BY의 `RANGE INTERVAL '6 days' PRECEDING`이 현재일 포함 7 calendar days를 뜻한다.
실행 순서
- business_tx를 날짜별 SUM한다.
- 한 날짜 한 행을 만든다.
- calendar range window를 적용한다.
- 누락일·ROWS 반례와 fixture oracle을 대조한다.
W22 조각별 정밀 해설
F09-C01 · 원문 1–10줄
- 문법 해부
- 1~10줄의 `원문 1–10줄`을 입력·guard·관찰·cleanup 단계로 나눈다.
- 실제 값 추적
- 항목 전체 흐름에 연결해 `daily grain`을 대조한다. 이 값이 chunk 단독 산출이라는 뜻은 아니다.
- 정상 예
- 정상 예에서는 source 순서와 owner 계약이 일치해 `daily grain`을 관찰한다.
- 틀린 예·반례
- 반례에서는 선행 guard·stable order·cleanup을 생략한다. 동결 경계: workbook 제공 정답이 아니다.
- 착각 방지
- `원문 1–10줄`이 항목 전체 Green을 단독 증명한다고 읽지 않는다.
- 하지 않는 일
- 이 chunk가 책임지지 않는 범위: workbook 제공 정답이 아니다.
- 다음 연결
- 다음 source chunk의 입력 또는 최종 marker/SQL oracle로 결과를 넘긴다.
F09-C02 · 원문 11–20줄
- 문법 해부
- 11~20줄의 `원문 11–20줄`을 입력·guard·관찰·cleanup 단계로 나눈다.
- 실제 값 추적
- 항목 전체 흐름에 연결해 `RANGE 6 days preceding`을 대조한다. 이 값이 chunk 단독 산출이라는 뜻은 아니다.
- 정상 예
- 정상 예에서는 source 순서와 owner 계약이 일치해 `RANGE 6 days preceding`을 관찰한다.
- 틀린 예·반례
- 반례에서는 선행 guard·stable order·cleanup을 생략한다. 동결 경계: 모든 status 포함은 명시한 학습 가정이다.
- 착각 방지
- `원문 11–20줄`이 항목 전체 Green을 단독 증명한다고 읽지 않는다.
- 하지 않는 일
- 이 chunk가 책임지지 않는 범위: 모든 status 포함은 명시한 학습 가정이다.
- 다음 연결
- 다음 source chunk의 입력 또는 최종 marker/SQL oracle로 결과를 넘긴다.
F09-C03 · 원문 21–27줄
- 문법 해부
- 21~27줄의 `원문 21–27줄`을 입력·guard·관찰·cleanup 단계로 나눈다.
- 실제 값 추적
- 항목 전체 흐름에 연결해 `fixture rows=9`을 대조한다. 이 값이 chunk 단독 산출이라는 뜻은 아니다.
- 정상 예
- 정상 예에서는 source 순서와 owner 계약이 일치해 `fixture rows=9`을 관찰한다.
- 틀린 예·반례
- 반례에서는 선행 guard·stable order·cleanup을 생략한다. 동결 경계: 누락일 자체를 0행으로 생성하지 않는다.
- 착각 방지
- `원문 21–27줄`이 항목 전체 Green을 단독 증명한다고 읽지 않는다.
- 하지 않는 일
- 이 chunk가 책임지지 않는 범위: 누락일 자체를 0행으로 생성하지 않는다.
- 다음 연결
- 다음 source chunk의 입력 또는 최종 marker/SQL oracle로 결과를 넘긴다.
반례
-
겉보기에는 맞지만 깨지는 예는?
-
SUM(amount)를 거래 row에 바로 window한다
-
그 상태는 owner·입력·관찰 중 한 칸이 비어 있어.
-
수정한 뒤 같은 source와 hash로 다시 대조해.
STEP 08 / 13
실제 값 따라가기
같은 입력값이 어느 줄을 지나 어떤 결과가 되는지 추적합니다.
| 순서 | 들어온 값 | 코드가 하는 일 | 나온 값·상태 | 경계 |
|---|---|---|---|---|
| F09-T01 초기 | 2026-06-30 | daily SUM | 2129999 | 모든 status 포함 가정 |
| F09-T02 누락 뒤 | 2026-12-28 | 6-day range | 303 | 7행 frame이면 옛 7월행 포함 |
| F09-T03 마지막 | 2027-01-02 | range sum | daily4200/moving1205002 | 누락일 0행은 생성 안 함 |
책임 경계
-
이 항목의 마지막 책임선은?
-
직접 역할은 `비정본 calendar-window SQL 예시`이야.
-
대표 경계는 `ROWS 6 PRECEDING과 의미가 다르다`이야.
-
정본/비정본 label과 evidence owner까지 확인하면 끝이야.
STEP 09 / 13
GitHub·AWS·PowerShell·PostgreSQL 내부에서 벌어지는 일
GitHub·AWS·PowerShell·PostgreSQL에서 실제로 일어나는 일과 증명 범위를 구분합니다.
21개 거래를 9개 observed date row로 만든다.
status filter 정책은 prompt에 없어 가정이다.값 기준 날짜 범위를 현재 row마다 정한다.
ROWS는 물리 행 수 기준이다.generate_series가 있어야 누락일도 0행으로 출력된다.
현재 query는 관찰된 날짜만 낸다.STEP 10 / 13
흔한 착각과 틀린 예
그럴듯하지만 틀린 해석을 반례로 고칩니다.
❌ SUM(amount)를 거래 row에 바로 window한다
왜 틀리나 비정본 calendar-window SQL 예시의 owner·관찰·경계 중 적어도 하나를 건너뛴다.
바르게 읽기 business_tx를 날짜별 SUM한다. 그리고 source의 실제 값과 hash를 다시 대조한다.
반례 반례에서는 `workbook 제공 정답이 아니다` 상태인데도 Green을 주장하게 된다.
❌ ROWS 6 PRECEDING을 7일이라고 부른다
왜 틀리나 비정본 calendar-window SQL 예시의 owner·관찰·경계 중 적어도 하나를 건너뛴다.
바르게 읽기 한 날짜 한 행을 만든다. 그리고 source의 실제 값과 hash를 다시 대조한다.
반례 반례에서는 `모든 status 포함은 명시한 학습 가정이다` 상태인데도 Green을 주장하게 된다.
❌ 누락일이 자동 0행으로 생긴다고 본다
왜 틀리나 비정본 calendar-window SQL 예시의 owner·관찰·경계 중 적어도 하나를 건너뛴다.
바르게 읽기 calendar range window를 적용한다. 그리고 source의 실제 값과 hash를 다시 대조한다.
반례 반례에서는 `누락일 자체를 0행으로 생성하지 않는다` 상태인데도 Green을 주장하게 된다.
❌ status filter를 설명 없이 추가한다
왜 틀리나 비정본 calendar-window SQL 예시의 owner·관찰·경계 중 적어도 하나를 건너뛴다.
바르게 읽기 누락일·ROWS 반례와 fixture oracle을 대조한다. 그리고 source의 실제 값과 hash를 다시 대조한다.
반례 반례에서는 `ROWS 6 PRECEDING과 의미가 다르다` 상태인데도 Green을 주장하게 된다.
❌ Q35를 workbook 정본 답안이라 부른다
왜 틀리나 비정본 calendar-window SQL 예시의 owner·관찰·경계 중 적어도 하나를 건너뛴다.
바르게 읽기 누락일·ROWS 반례와 fixture oracle을 대조한다. 그리고 source의 실제 값과 hash를 다시 대조한다.
반례 반례에서는 `workbook 제공 정답이 아니다` 상태인데도 Green을 주장하게 된다.
STEP 11 / 13
이 코드가 보장하지 않는 것
이 코드가 책임지지 않는 일을 분리합니다.
workbook 제공 정답이 아니다
이 책임을 맡는 곳: 별도 외부/selector 실행모든 status 포함은 명시한 학습 가정이다
이 책임을 맡는 곳: secret·운영 정책누락일 자체를 0행으로 생성하지 않는다
이 책임을 맡는 곳: infrastructure·사람 검토ROWS 6 PRECEDING과 의미가 다르다
이 책임을 맡는 곳: owner lifecycleSTEP 12 / 13
직접 다시 써보기
뜻 → 조각 → 전체 코드 순서로 다시 씁니다.
1단계 · 뜻부터 복원
다음 역할을 고정값과 미보장 경계까지 말한다: business_date별 합계를 먼저 만들고 calendar 7일 범위를 RANGE window frame으로 계산하는 비정본 Q35 예시다.
2단계 · 코드 조각 재조립
- 원문 1–10줄
- 원문 11–20줄
- 원문 21–27줄
3단계 · 파일 전체 다시 쓰기
27개 물리 줄을 원본 순서로 복원하고 SHA-256 a8602cb326d8e4cc237b1401ea736490489a74f6a5bb62636f9c55665d4cc773와 대조한다.
자가 점검
- 원본 source/template bytes를 바꾸지 않았는가?
- 외부 미실행과 local restore Green을 구분했는가?
- secret 원문을 evidence에 남기지 않았는가?
- D7 checked_at 충돌과 사람 검토 경계를 보았는가?
- Q35/Q36을 workbook 정본 답안이라고 부르지 않았는가?
STEP 13 / 13
전체 원본 source
감사로 고정한 전체 source를 가감 없이 확인합니다.
학습용 예시 전체 확인하기 · 정본 답안 아님
-- 학습용 예시 · 정본 답안 아님: workbook은 W22-SQL-Q35 답안을 제공하지 않는다.
-- 입력 grain: business_tx 한 행 = 거래 한 건. 출력 grain: business_date 한 행 = 그 날짜의 합계와 7일 이동합계.
-- 학습 가정: prompt에 status filter가 없으므로 SUCCESS·FAILED·UNKNOWN·PROCESSING을 모두 포함한다.
-- 핵심 반례: 누락일이 많아도 ROWS 6 PRECEDING은 최근 7개 '행'을 세므로 7개 달력일과 다르다.
SET search_path TO workbook_schema, public;
WITH daily AS (
SELECT
business_date,
SUM(amount) AS daily_amount
FROM business_tx
GROUP BY business_date
)
SELECT
business_date,
daily_amount,
SUM(daily_amount) OVER (
ORDER BY business_date::timestamp
RANGE BETWEEN INTERVAL '6 days' PRECEDING AND CURRENT ROW
) AS moving_7_calendar_days
FROM daily
ORDER BY business_date;
-- fixture oracle: 9행. 2026-06-30=2129999, 2026-07-01 이동합계=2132199.
-- fixture oracle: 긴 누락 뒤 2026-12-28 이동합계는 303으로 다시 시작한다.
-- fixture oracle: 2027-01-02 daily_amount=4200, moving_7_calendar_days=1205002.
-- 누락일도 0행으로 출력해야 한다면 generate_series 달력과 LEFT JOIN을 추가해야 한다.
10W22-SQL-Q36 — NOT EXISTS와 FK 정상계의 0행 oracle
illustrative/sql/W22-SQL-Q36.sql
학습용 예시 · 정본 답안 아님 · 학습용 예시 · 정본 답안 아님 · W22-F1023줄 연결23줄 번역3 chunks
W22-SQL-Q36 — NOT EXISTS와 FK 정상계의 0행 oracle
illustrative/sql/W22-SQL-Q36.sql
학습용 예시 · 정본 답안 아님 · 학습용 예시 · 정본 답안 아님 · W22-F10STEP 01 / 13
오늘 이 코드에서 해결할 문제
무엇을 이해해야 하는지 질문부터 잡습니다.
ledger_entry를 시작으로 NOT EXISTS anti join을 써서 business_tx가 없는 고아 원장을 찾는 비정본 Q36 예시다.
- `NOT EXISTS`은 어느 줄에서 생길까?
- 입력→guard→관찰→cleanup 순서는 무엇인가?
- local owner와 external human review는 누구인가?
- 직접 관찰하지 않은 Green은 무엇인가?
- 반례는 `workbook 제공 정답이 아니다`이라는 경계와 어떻게 연결되는가?
NOT EXISTSledger grainfixture rows=0NOT NULL FKisolated broken-table counterexampleSTEP 02 / 13
아주 짧게: 이 코드는 왜 필요할까?
웹소설 대신 이 코드가 필요한 이유만 두 문단으로 쉽게 봅니다.
STARRY가 GitHub run표·AWS 출입증·DB 복구 영수증·SQL 결과표를 서로 다른 칸에 놓는다.
W22-SQL-Q36 — NOT EXISTS와 FK 정상계의 0행 oracle ― 증거 흐름으로 바꾸기
ledger_entry를 시작으로 NOT EXISTS anti join을 써서 business_tx가 없는 고아 원장을 찾는 비정본 Q36 예시다.
핵심값 NOT EXISTS, ledger grain, fixture rows=0, NOT NULL FK, isolated broken-table counterexample을 원본 줄로 따라가되, `workbook 제공 정답이 아니다`까지 함께 표시해 Green 범위를 부풀리지 않는다.
딱 여기까지만 비유는 owner와 순서를 기억하게 할 뿐 외부 실행·AWS 계정 상태·PostgreSQL restore·SQL 결과를 자동 증명하지 않는다.
STEP 03 / 13
초등학생도 이해하는 설명
생활 비유와 실제 코드의 경계를 함께 확인합니다.
원문 1–10줄
1~10줄을 한 덩어리로 읽어 1번째 움직임을 본다. ledger_entry를 시작으로 NOT EXISTS anti join을 써서 business_tx가 없는 고아 원장을 찾는 비정본 Q36 예시다.
- 코드 연결
1~10줄- 비유
- 원장 카드마다 거래 원본 보관함을 찾아보고, 짝이 하나도 없는 카드만 남기는 분실물 검사
- 비유의 끝
- workbook 제공 정답이 아니다
원문 11–20줄
11~20줄을 한 덩어리로 읽어 2번째 움직임을 본다. ledger_entry를 시작으로 NOT EXISTS anti join을 써서 business_tx가 없는 고아 원장을 찾는 비정본 Q36 예시다.
- 코드 연결
11~20줄- 비유
- 원장 카드마다 거래 원본 보관함을 찾아보고, 짝이 하나도 없는 카드만 남기는 분실물 검사
- 비유의 끝
- 정상 fixture에서는 FK 때문에 0행이다
원문 21–25줄
21~25줄을 한 덩어리로 읽어 3번째 움직임을 본다. ledger_entry를 시작으로 NOT EXISTS anti join을 써서 business_tx가 없는 고아 원장을 찾는 비정본 Q36 예시다.
- 코드 연결
21~25줄- 비유
- 원장 카드마다 거래 원본 보관함을 찾아보고, 짝이 하나도 없는 카드만 남기는 분실물 검사
- 비유의 끝
- production FK를 제거하지 않는다
문제의 첫 장면
-
첫 고정값은 `NOT EXISTS` 맞아?
-
ledger_entry를 시작으로 NOT EXISTS anti join을 써서 business_tx가 없는 고아 원장을 찾는 비정본 Q36 예시다.
-
원문에서 `NOT EXISTS`이 생기는 위치를 찾자.
-
그리고 `workbook 제공 정답이 아니다`도 같이 적어.
입력에서 결과까지
-
`ledger grain`은 언제 생겨?
-
ledger_entry를 시작 grain으로 읽는다. → 각 tx_id의 business_tx 존재를 찾는다.
-
존재하지 않는 원장만 남긴다. → FK 정상 fixture의 0행 이유를 설명한다.
-
관찰값과 `정상 fixture에서는 FK 때문에 0행이다`을 분리하면 돼.
STEP 04 / 13
비유 ↔ 코드 전체 연결표
감사 규칙상 연결 대상인 원본 23줄을 빠짐없이 연결합니다.
| 줄 | 정확한 원본 줄 | STARRY 비유 | 실제 뜻·입력·결과·한계 |
|---|---|---|---|
| 1줄F10-L01 | -- 학습용 예시 · 정본 답안 아님: |
원장 카드마다 거래 원본 보관함을 찾아보고, 짝이 하나도 없는 카드만 남기는 분실물 검사 | 이 source의 비정본 provenance, 가정, 반례, 또는 실행 경계를 사람이 확인할 주석이다.
|
| 2줄F10-L02 | -- 입력 grain: |
원장 카드마다 거래 원본 보관함을 찾아보고, 짝이 하나도 없는 카드만 남기는 분실물 검사 | 이 source의 비정본 provenance, 가정, 반례, 또는 실행 경계를 사람이 확인할 주석이다.
|
| 3줄F10-L03 | -- 핵심 도구: |
원장 카드마다 거래 원본 보관함을 찾아보고, 짝이 하나도 없는 카드만 남기는 분실물 검사 | matching business_tx가 없는 ledger row만 남기는 anti join 조건을 연다.
|
| 4줄F10-L04 | SET search_path TO workbook_schema, |
원장 카드마다 거래 원본 보관함을 찾아보고, 짝이 하나도 없는 카드만 남기는 분실물 검사 | 비정본 anti-join SQL 예시의 4번째 원문을 앞 guard와 뒤 관찰값 사이에 연결한다.
|
| 6줄F10-L06 | SELECT |
원장 카드마다 거래 원본 보관함을 찾아보고, 짝이 하나도 없는 카드만 남기는 분실물 검사 | SQL의 입력 grain·필터·집계·stable 출력 순서를 구성하는 절이다.
|
| 7줄F10-L07 | le. |
원장 카드마다 거래 원본 보관함을 찾아보고, 짝이 하나도 없는 카드만 남기는 분실물 검사 | 비정본 anti-join SQL 예시의 7번째 원문을 앞 guard와 뒤 관찰값 사이에 연결한다.
|
| 8줄F10-L08 | le. |
원장 카드마다 거래 원본 보관함을 찾아보고, 짝이 하나도 없는 카드만 남기는 분실물 검사 | 비정본 anti-join SQL 예시의 8번째 원문을 앞 guard와 뒤 관찰값 사이에 연결한다.
|
| 9줄F10-L09 | le. |
원장 카드마다 거래 원본 보관함을 찾아보고, 짝이 하나도 없는 카드만 남기는 분실물 검사 | 비정본 anti-join SQL 예시의 9번째 원문을 앞 guard와 뒤 관찰값 사이에 연결한다.
|
| 10줄F10-L10 | le. |
원장 카드마다 거래 원본 보관함을 찾아보고, 짝이 하나도 없는 카드만 남기는 분실물 검사 | 비정본 anti-join SQL 예시의 10번째 원문을 앞 guard와 뒤 관찰값 사이에 연결한다.
|
| 11줄F10-L11 | le. |
원장 카드마다 거래 원본 보관함을 찾아보고, 짝이 하나도 없는 카드만 남기는 분실물 검사 | 비정본 anti-join SQL 예시의 11번째 원문을 앞 guard와 뒤 관찰값 사이에 연결한다.
|
| 12줄F10-L12 | le. |
원장 카드마다 거래 원본 보관함을 찾아보고, 짝이 하나도 없는 카드만 남기는 분실물 검사 | 비정본 anti-join SQL 예시의 12번째 원문을 앞 guard와 뒤 관찰값 사이에 연결한다.
|
| 13줄F10-L13 | le. |
원장 카드마다 거래 원본 보관함을 찾아보고, 짝이 하나도 없는 카드만 남기는 분실물 검사 | 비정본 anti-join SQL 예시의 13번째 원문을 앞 guard와 뒤 관찰값 사이에 연결한다.
|
| 14줄F10-L14 | FROM ledger_entry AS le |
원장 카드마다 거래 원본 보관함을 찾아보고, 짝이 하나도 없는 카드만 남기는 분실물 검사 | SQL의 입력 grain·필터·집계·stable 출력 순서를 구성하는 절이다.
|
| 15줄F10-L15 | WHERE NOT EXISTS ( |
원장 카드마다 거래 원본 보관함을 찾아보고, 짝이 하나도 없는 카드만 남기는 분실물 검사 | matching business_tx가 없는 ledger row만 남기는 anti join 조건을 연다.
|
| 16줄F10-L16 | SELECT 1 |
원장 카드마다 거래 원본 보관함을 찾아보고, 짝이 하나도 없는 카드만 남기는 분실물 검사 | SQL의 입력 grain·필터·집계·stable 출력 순서를 구성하는 절이다.
|
| 17줄F10-L17 | FROM business_tx AS tx |
원장 카드마다 거래 원본 보관함을 찾아보고, 짝이 하나도 없는 카드만 남기는 분실물 검사 | SQL의 입력 grain·필터·집계·stable 출력 순서를 구성하는 절이다.
|
| 18줄F10-L18 | WHERE tx. |
원장 카드마다 거래 원본 보관함을 찾아보고, 짝이 하나도 없는 카드만 남기는 분실물 검사 | outer ledger tx_id와 inner transaction tx_id를 상관 equality로 연결한다.
|
| 19줄F10-L19 | ) |
원장 카드마다 거래 원본 보관함을 찾아보고, 짝이 하나도 없는 카드만 남기는 분실물 검사 | 현재 object·array·block 또는 query 범위를 열거나 닫아 구조를 유지한다.
|
| 20줄F10-L20 | ORDER BY le. |
원장 카드마다 거래 원본 보관함을 찾아보고, 짝이 하나도 없는 카드만 남기는 분실물 검사 | SQL의 입력 grain·필터·집계·stable 출력 순서를 구성하는 절이다.
|
| 22줄F10-L22 | -- canonical fixture oracle: |
원장 카드마다 거래 원본 보관함을 찾아보고, 짝이 하나도 없는 카드만 남기는 분실물 검사 | 이 source의 비정본 provenance, 가정, 반례, 또는 실행 경계를 사람이 확인할 주석이다.
|
| 23줄F10-L23 | -- 이유: |
원장 카드마다 거래 원본 보관함을 찾아보고, 짝이 하나도 없는 카드만 남기는 분실물 검사 | 이 source의 비정본 provenance, 가정, 반례, 또는 실행 경계를 사람이 확인할 주석이다.
|
| 24줄F10-L24 | -- 따라서 정상 제약을 켠 채로는 '원장은 있으나 거래가 없는' 고아 행을 INSERT할 수 없다. |
원장 카드마다 거래 원본 보관함을 찾아보고, 짝이 하나도 없는 카드만 남기는 분실물 검사 | 이 source의 비정본 provenance, 가정, 반례, 또는 실행 경계를 사람이 확인할 주석이다.
|
| 25줄F10-L25 | -- 반례는 FK를 제거한 격리 복제 table 또는 제약이 깨진 import snapshot에서만 만들고 production table은 바꾸지 않는다. |
원장 카드마다 거래 원본 보관함을 찾아보고, 짝이 하나도 없는 카드만 남기는 분실물 검사 | 이 source의 비정본 provenance, 가정, 반례, 또는 실행 경계를 사람이 확인할 주석이다.
|
Green 범위
-
marker나 파일이 보이면 전부 성공이야?
-
아니. source가 직접 검증한 범위만 말해야 해.
-
직접 연결되는 대표 값은 `isolated broken-table counterexample`이야.
-
`production FK를 제거하지 않는다`는 별도 증거가 필요해.
STEP 05 / 13
원본 코드 조각
원본을 3개 의미 조각으로 나누어 그대로 확인합니다.
파일을 한꺼번에 외우지 않고 실행 의미가 이어지는 작은 조각으로 봅니다. 아래 코드는 prompt·fixture·가정을 밝힌 학습용 예시 source이며, 제공 정본 답안이 아닙니다.
-- 학습용 예시 · 정본 답안 아님: workbook은 W22-SQL-Q36 답안을 제공하지 않는다.
-- 입력 grain: ledger_entry 한 행 = 원장 entry. 출력 grain: 참조 business_tx가 없는 원장 entry 한 행.
-- 핵심 도구: NOT EXISTS anti join. NULL 비교 함정이 있는 NOT IN보다 의도가 직접적이다.
SET search_path TO workbook_schema, public;
SELECT
le.entry_id,
le.tx_id,
le.request_id,
le.account_id,
le.entry_type,
le.signed_amount,
le.occurred_at
FROM ledger_entry AS le
WHERE NOT EXISTS (
SELECT 1
FROM business_tx AS tx
WHERE tx.tx_id = le.tx_id
)
ORDER BY le.entry_id;
-- canonical fixture oracle: 0행.
-- 이유: ledger_entry.tx_id는 NOT NULL이면서 business_tx(tx_id)를 참조하는 즉시 FK다.
-- 따라서 정상 제약을 켠 채로는 '원장은 있으나 거래가 없는' 고아 행을 INSERT할 수 없다.
-- 반례는 FK를 제거한 격리 복제 table 또는 제약이 깨진 import snapshot에서만 만들고 production table은 바꾸지 않는다.
STEP 06 / 13
코드 한 줄씩 한국어로 번역
비어 있지 않은 23줄을 모두 한국어로 옮깁니다.
비어 있지 않은 원본 줄은 하나도 생략하지 않습니다.
| 줄 | 원본 | 한국어 번역 |
|---|---|---|
| 1 | -- 학습용 예시 · 정본 답안 아님: workbook은 W22-SQL-Q36 답안을 제공하지 않는다. | 이 source의 비정본 provenance, 가정, 반례, 또는 실행 경계를 사람이 확인할 주석이다. |
| 2 | -- 입력 grain: ledger_entry 한 행 = 원장 entry. 출력 grain: 참조 business_tx가 없는 원장 entry 한 행. | 이 source의 비정본 provenance, 가정, 반례, 또는 실행 경계를 사람이 확인할 주석이다. |
| 3 | -- 핵심 도구: NOT EXISTS anti join. NULL 비교 함정이 있는 NOT IN보다 의도가 직접적이다. | matching business_tx가 없는 ledger row만 남기는 anti join 조건을 연다. |
| 4 | SET search_path TO workbook_schema, public; | 비정본 anti-join SQL 예시의 4번째 원문을 앞 guard와 뒤 관찰값 사이에 연결한다. |
| 6 | SELECT | SQL의 입력 grain·필터·집계·stable 출력 순서를 구성하는 절이다. |
| 7 | le.entry_id, | 비정본 anti-join SQL 예시의 7번째 원문을 앞 guard와 뒤 관찰값 사이에 연결한다. |
| 8 | le.tx_id, | 비정본 anti-join SQL 예시의 8번째 원문을 앞 guard와 뒤 관찰값 사이에 연결한다. |
| 9 | le.request_id, | 비정본 anti-join SQL 예시의 9번째 원문을 앞 guard와 뒤 관찰값 사이에 연결한다. |
| 10 | le.account_id, | 비정본 anti-join SQL 예시의 10번째 원문을 앞 guard와 뒤 관찰값 사이에 연결한다. |
| 11 | le.entry_type, | 비정본 anti-join SQL 예시의 11번째 원문을 앞 guard와 뒤 관찰값 사이에 연결한다. |
| 12 | le.signed_amount, | 비정본 anti-join SQL 예시의 12번째 원문을 앞 guard와 뒤 관찰값 사이에 연결한다. |
| 13 | le.occurred_at | 비정본 anti-join SQL 예시의 13번째 원문을 앞 guard와 뒤 관찰값 사이에 연결한다. |
| 14 | FROM ledger_entry AS le | SQL의 입력 grain·필터·집계·stable 출력 순서를 구성하는 절이다. |
| 15 | WHERE NOT EXISTS ( | matching business_tx가 없는 ledger row만 남기는 anti join 조건을 연다. |
| 16 | SELECT 1 | SQL의 입력 grain·필터·집계·stable 출력 순서를 구성하는 절이다. |
| 17 | FROM business_tx AS tx | SQL의 입력 grain·필터·집계·stable 출력 순서를 구성하는 절이다. |
| 18 | WHERE tx.tx_id = le.tx_id | outer ledger tx_id와 inner transaction tx_id를 상관 equality로 연결한다. |
| 19 | ) | 현재 object·array·block 또는 query 범위를 열거나 닫아 구조를 유지한다. |
| 20 | ORDER BY le.entry_id; | SQL의 입력 grain·필터·집계·stable 출력 순서를 구성하는 절이다. |
| 22 | -- canonical fixture oracle: 0행. | 이 source의 비정본 provenance, 가정, 반례, 또는 실행 경계를 사람이 확인할 주석이다. |
| 23 | -- 이유: ledger_entry.tx_id는 NOT NULL이면서 business_tx(tx_id)를 참조하는 즉시 FK다. | 이 source의 비정본 provenance, 가정, 반례, 또는 실행 경계를 사람이 확인할 주석이다. |
| 24 | -- 따라서 정상 제약을 켠 채로는 '원장은 있으나 거래가 없는' 고아 행을 INSERT할 수 없다. | 이 source의 비정본 provenance, 가정, 반례, 또는 실행 경계를 사람이 확인할 주석이다. |
| 25 | -- 반례는 FK를 제거한 격리 복제 table 또는 제약이 깨진 import snapshot에서만 만들고 production table은 바꾸지 않는다. | 이 source의 비정본 provenance, 가정, 반례, 또는 실행 경계를 사람이 확인할 주석이다. |
STEP 07 / 13
기존 수준의 한 줄 읽기·문법 해부
쉬운 설명 다음에 문법과 실행 순서를 정밀하게 읽습니다.
한 줄로 읽기ledger_entry를 시작으로 NOT EXISTS anti join을 써서 business_tx가 없는 고아 원장을 찾는 비정본 Q36 예시다. 다만 workbook 제공 정답이 아니다
문법 해부
- `NOT EXISTS`는 현재 ledger row와 같은 tx_id의 business_tx가 하나라도 있는지 반대로 검사한다.
- 상관 subquery의 equality가 outer `le.tx_id`를 inner `tx.tx_id`와 연결한다.
실행 순서
- ledger_entry를 시작 grain으로 읽는다.
- 각 tx_id의 business_tx 존재를 찾는다.
- 존재하지 않는 원장만 남긴다.
- FK 정상 fixture의 0행 이유를 설명한다.
W22 조각별 정밀 해설
F10-C01 · 원문 1–10줄
- 문법 해부
- 1~10줄의 `원문 1–10줄`을 입력·guard·관찰·cleanup 단계로 나눈다.
- 실제 값 추적
- 항목 전체 흐름에 연결해 `NOT EXISTS`을 대조한다. 이 값이 chunk 단독 산출이라는 뜻은 아니다.
- 정상 예
- 정상 예에서는 source 순서와 owner 계약이 일치해 `NOT EXISTS`을 관찰한다.
- 틀린 예·반례
- 반례에서는 선행 guard·stable order·cleanup을 생략한다. 동결 경계: workbook 제공 정답이 아니다.
- 착각 방지
- `원문 1–10줄`이 항목 전체 Green을 단독 증명한다고 읽지 않는다.
- 하지 않는 일
- 이 chunk가 책임지지 않는 범위: workbook 제공 정답이 아니다.
- 다음 연결
- 다음 source chunk의 입력 또는 최종 marker/SQL oracle로 결과를 넘긴다.
F10-C02 · 원문 11–20줄
- 문법 해부
- 11~20줄의 `원문 11–20줄`을 입력·guard·관찰·cleanup 단계로 나눈다.
- 실제 값 추적
- 항목 전체 흐름에 연결해 `ledger grain`을 대조한다. 이 값이 chunk 단독 산출이라는 뜻은 아니다.
- 정상 예
- 정상 예에서는 source 순서와 owner 계약이 일치해 `ledger grain`을 관찰한다.
- 틀린 예·반례
- 반례에서는 선행 guard·stable order·cleanup을 생략한다. 동결 경계: 정상 fixture에서는 FK 때문에 0행이다.
- 착각 방지
- `원문 11–20줄`이 항목 전체 Green을 단독 증명한다고 읽지 않는다.
- 하지 않는 일
- 이 chunk가 책임지지 않는 범위: 정상 fixture에서는 FK 때문에 0행이다.
- 다음 연결
- 다음 source chunk의 입력 또는 최종 marker/SQL oracle로 결과를 넘긴다.
F10-C03 · 원문 21–25줄
- 문법 해부
- 21~25줄의 `원문 21–25줄`을 입력·guard·관찰·cleanup 단계로 나눈다.
- 실제 값 추적
- 항목 전체 흐름에 연결해 `fixture rows=0`을 대조한다. 이 값이 chunk 단독 산출이라는 뜻은 아니다.
- 정상 예
- 정상 예에서는 source 순서와 owner 계약이 일치해 `fixture rows=0`을 관찰한다.
- 틀린 예·반례
- 반례에서는 선행 guard·stable order·cleanup을 생략한다. 동결 경계: production FK를 제거하지 않는다.
- 착각 방지
- `원문 21–25줄`이 항목 전체 Green을 단독 증명한다고 읽지 않는다.
- 하지 않는 일
- 이 chunk가 책임지지 않는 범위: production FK를 제거하지 않는다.
- 다음 연결
- 다음 source chunk의 입력 또는 최종 marker/SQL oracle로 결과를 넘긴다.
반례
-
겉보기에는 맞지만 깨지는 예는?
-
FROM business_tx로 시작해 고아 ledger를 잃는다
-
그 상태는 owner·입력·관찰 중 한 칸이 비어 있어.
-
수정한 뒤 같은 source와 hash로 다시 대조해.
STEP 08 / 13
실제 값 따라가기
같은 입력값이 어느 줄을 지나 어떤 결과가 되는지 추적합니다.
| 순서 | 들어온 값 | 코드가 하는 일 | 나온 값·상태 | 경계 |
|---|---|---|---|---|
| F10-T01 normal | 16 ledger rows | anti join | 0 orphan | query 실패가 아님 |
| F10-T02 constraint | NOT NULL FK | insert guard | orphan 생성 거절 | immediate FK |
| F10-T03 counterexample | isolated broken copy | same NOT EXISTS | orphan 발견 | production FK 제거 금지 |
책임 경계
-
이 항목의 마지막 책임선은?
-
직접 역할은 `비정본 anti-join SQL 예시`이야.
-
대표 경계는 `0행은 query 실패가 아니라 제약이 지켜진 결과다`이야.
-
정본/비정본 label과 evidence owner까지 확인하면 끝이야.
STEP 09 / 13
GitHub·AWS·PowerShell·PostgreSQL 내부에서 벌어지는 일
GitHub·AWS·PowerShell·PostgreSQL에서 실제로 일어나는 일과 증명 범위를 구분합니다.
각 outer row에 matching inner row가 없을 때만 출력한다.
NOT IN의 NULL 의미와 다르다.ledger tx_id가 존재하는 business_tx를 참조하게 한다.
disable/import corruption 상황은 별도다.PostgreSQL이 NOT EXISTS를 anti-join plan으로 바꿀 수 있다.
plan 형태보다 결과 grain이 우선이다.STEP 10 / 13
흔한 착각과 틀린 예
그럴듯하지만 틀린 해석을 반례로 고칩니다.
❌ FROM business_tx로 시작해 고아 ledger를 잃는다
왜 틀리나 비정본 anti-join SQL 예시의 owner·관찰·경계 중 적어도 하나를 건너뛴다.
바르게 읽기 ledger_entry를 시작 grain으로 읽는다. 그리고 source의 실제 값과 hash를 다시 대조한다.
반례 반례에서는 `workbook 제공 정답이 아니다` 상태인데도 Green을 주장하게 된다.
❌ NOT IN NULL 함정을 설명하지 않는다
왜 틀리나 비정본 anti-join SQL 예시의 owner·관찰·경계 중 적어도 하나를 건너뛴다.
바르게 읽기 각 tx_id의 business_tx 존재를 찾는다. 그리고 source의 실제 값과 hash를 다시 대조한다.
반례 반례에서는 `정상 fixture에서는 FK 때문에 0행이다` 상태인데도 Green을 주장하게 된다.
❌ 0행이면 SQL이 틀렸다고 본다
왜 틀리나 비정본 anti-join SQL 예시의 owner·관찰·경계 중 적어도 하나를 건너뛴다.
바르게 읽기 존재하지 않는 원장만 남긴다. 그리고 source의 실제 값과 hash를 다시 대조한다.
반례 반례에서는 `production FK를 제거하지 않는다` 상태인데도 Green을 주장하게 된다.
❌ 반례를 위해 production FK를 제거한다
왜 틀리나 비정본 anti-join SQL 예시의 owner·관찰·경계 중 적어도 하나를 건너뛴다.
바르게 읽기 FK 정상 fixture의 0행 이유를 설명한다. 그리고 source의 실제 값과 hash를 다시 대조한다.
반례 반례에서는 `0행은 query 실패가 아니라 제약이 지켜진 결과다` 상태인데도 Green을 주장하게 된다.
❌ Q36을 workbook 정본 답안이라 부른다
왜 틀리나 비정본 anti-join SQL 예시의 owner·관찰·경계 중 적어도 하나를 건너뛴다.
바르게 읽기 FK 정상 fixture의 0행 이유를 설명한다. 그리고 source의 실제 값과 hash를 다시 대조한다.
반례 반례에서는 `workbook 제공 정답이 아니다` 상태인데도 Green을 주장하게 된다.
STEP 11 / 13
이 코드가 보장하지 않는 것
이 코드가 책임지지 않는 일을 분리합니다.
workbook 제공 정답이 아니다
이 책임을 맡는 곳: 별도 외부/selector 실행정상 fixture에서는 FK 때문에 0행이다
이 책임을 맡는 곳: secret·운영 정책production FK를 제거하지 않는다
이 책임을 맡는 곳: infrastructure·사람 검토0행은 query 실패가 아니라 제약이 지켜진 결과다
이 책임을 맡는 곳: owner lifecycleSTEP 12 / 13
직접 다시 써보기
뜻 → 조각 → 전체 코드 순서로 다시 씁니다.
1단계 · 뜻부터 복원
다음 역할을 고정값과 미보장 경계까지 말한다: ledger_entry를 시작으로 NOT EXISTS anti join을 써서 business_tx가 없는 고아 원장을 찾는 비정본 Q36 예시다.
2단계 · 코드 조각 재조립
- 원문 1–10줄
- 원문 11–20줄
- 원문 21–25줄
3단계 · 파일 전체 다시 쓰기
25개 물리 줄을 원본 순서로 복원하고 SHA-256 4b5386b1980438dd71e7733124a273ada398a924cd0ad4e5beb6e4f35010c12e와 대조한다.
자가 점검
- 원본 source/template bytes를 바꾸지 않았는가?
- 외부 미실행과 local restore Green을 구분했는가?
- secret 원문을 evidence에 남기지 않았는가?
- D7 checked_at 충돌과 사람 검토 경계를 보았는가?
- Q35/Q36을 workbook 정본 답안이라고 부르지 않았는가?
STEP 13 / 13
전체 원본 source
감사로 고정한 전체 source를 가감 없이 확인합니다.
학습용 예시 전체 확인하기 · 정본 답안 아님
-- 학습용 예시 · 정본 답안 아님: workbook은 W22-SQL-Q36 답안을 제공하지 않는다.
-- 입력 grain: ledger_entry 한 행 = 원장 entry. 출력 grain: 참조 business_tx가 없는 원장 entry 한 행.
-- 핵심 도구: NOT EXISTS anti join. NULL 비교 함정이 있는 NOT IN보다 의도가 직접적이다.
SET search_path TO workbook_schema, public;
SELECT
le.entry_id,
le.tx_id,
le.request_id,
le.account_id,
le.entry_type,
le.signed_amount,
le.occurred_at
FROM ledger_entry AS le
WHERE NOT EXISTS (
SELECT 1
FROM business_tx AS tx
WHERE tx.tx_id = le.tx_id
)
ORDER BY le.entry_id;
-- canonical fixture oracle: 0행.
-- 이유: ledger_entry.tx_id는 NOT NULL이면서 business_tx(tx_id)를 참조하는 즉시 FK다.
-- 따라서 정상 제약을 켠 채로는 '원장은 있으나 거래가 없는' 고아 행을 INSERT할 수 없다.
-- 반례는 FK를 제거한 격리 복제 table 또는 제약이 깨진 import snapshot에서만 만들고 production table은 바꾸지 않는다.