W24 · 공통 거래 코어 v1 동결
24주차 코드 뒤풀이: exact test Gate부터 데모·리뷰·트랙·릴리스까지
37개 class·66개 test의 exact inventory와 43개 selector를 읽고, numeric accountId demo의 201→200→409→대사0 흐름, architecture·README·external review·track 선택의 사람 검토 경계, DB·host JVM cleanup까지 하나의 release evidence 사슬로 연결합니다. PDF 전문 정본 7개, ZIP 보조 계약 2개, 비정본 학습 예시 8개를 구분하며 실제 Gradle·Docker·HTTP·PostgreSQL·외부 review 실행 성공은 주장하지 않습니다.
01core-v1-expected.json — 37개 class·66개 test의 exact 계약
learning_stages/w24/overlay/core-v1-expected.json
패키지 정본 보조 계약 · exact JSON bytes · 정본 · W24-F011줄 연결1줄 번역1 chunks
core-v1-expected.json — 37개 class·66개 test의 exact 계약
learning_stages/w24/overlay/core-v1-expected.json
패키지 정본 보조 계약 · exact JSON bytes · 정본 · W24-F01STEP 01 / 13
오늘 이 코드에서 해결할 문제
무엇을 이해해야 하는지 질문부터 잡습니다.
coreV1Gate가 받아야 할 37개 JUnit class와 class별 test 수, selector 합계 43을 한 JSON 계약으로 고정한다.
- selectors=43은 어느 source와 실제 결과에서 확인해야 할까?
- 첫 실패를 만드는 조건과 fail-closed 지점은 어디일까?
- 왜 ‘목록 자체는 test 실행 결과가 아니다’를 별도 경계로 남겨야 할까?
selectors=43classes=37tests=66minified one-line JSON왜 필요한가 — core-v1-expected.json — 37개 class·66개 test의 exact 계약
-
selectors=43가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 coreV1Gate가 받아야 할 37개 JUnit class와 class별 test 수, selector 합계 43을 한 JSON 계약으로 고정한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘목록 자체는 test 실행 결과가 아니다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 selectors=43와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 02 / 13
아주 짧게: 이 코드는 왜 필요할까?
웹소설 대신 이 코드가 필요한 이유만 두 문단으로 쉽게 봅니다.
새 기능을 멈춘 팀이 코드·test·문서·demo를 같은 release 후보에 묶어 하나씩 검수한다.
검수 도장이 붙은 공통 거래 코어 출고 상자
이 파일은 coreV1Gate가 받아야 할 37개 JUnit class와 class별 test 수, selector 합계 43을 한 JSON 계약으로 고정한다. 눈으로 읽을 때는 각 줄을 검수표 한 칸처럼 보고, 입력과 다음 상태를 놓치지 않는다.
마지막 도장은 source shape와 실제 runtime·사람 검토를 구분한 뒤에만 찍는다. 특히 목록 자체는 test 실행 결과가 아니다
딱 여기까지만 비유는 실행 순서를 돕지만 실제 Gradle·Docker·DB·사람 review를 대신하지 않는다.
STEP 03 / 13
초등학생도 이해하는 설명
생활 비유와 실제 코드의 경계를 함께 확인합니다.
값 1: selectors=43
이 파일에서 계속 확인할 고정 단서가 selectors=43다.
- 코드 연결
F01 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- 목록 자체는 test 실행 결과가 아니다
값 2: classes=37
이 파일에서 계속 확인할 고정 단서가 classes=37다.
- 코드 연결
F01 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- unexpected class도 별도 검출해야 한다
값 3: tests=66
이 파일에서 계속 확인할 고정 단서가 tests=66다.
- 코드 연결
F01 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- skip은 성공으로 세지 않는다
값 4: minified one-line JSON
이 파일에서 계속 확인할 고정 단서가 minified one-line JSON다.
- 코드 연결
F01 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- 목록 자체는 test 실행 결과가 아니다
STEP 04 / 13
비유 ↔ 코드 전체 연결표
감사 규칙상 연결 대상인 원본 1줄을 빠짐없이 연결합니다.
| 줄 | 정확한 원본 줄 | STARRY 비유 | 실제 뜻·입력·결과·한계 |
|---|---|---|---|
| 1줄F01-L01 | { |
출고표 1번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 selector 총수를 JSON 계약에 고정한다.
|
STEP 05 / 13
원본 코드 조각
원본을 1개 의미 조각으로 나누어 그대로 확인합니다.
파일을 한꺼번에 외우지 않고 실행 의미가 이어지는 작은 조각으로 봅니다. 아래 코드는 hash로 고정한 native 정본 source에서 그대로 잘랐습니다.
{"selectors":43,"classes":{"com.example.financialcore.account.AccountJpaMappingTest":1,"com.example.financialcore.account.AccountServiceTest":1,"com.example.financialcore.account.AccountTest":5,"com.example.financialcore.account.api.AccountControllerHappyPathTest":1,"com.example.financialcore.account.api.AccountControllerPersistenceIT":1,"com.example.financialcore.account.api.AccountControllerTest":4,"com.example.financialcore.account.api.CreateAccountRequestValidationTest":1,"com.example.financialcore.account.ConcurrentWithdraw20IT":1,"com.example.financialcore.account.LostUpdateBaselineIT":2,"com.example.financialcore.account.OpeningIntegrationTest":1,"com.example.financialcore.account.OptimisticAccountIT":1,"com.example.financialcore.api.ApiExceptionHandlerTest":1,"com.example.financialcore.api.RequestIdFilterTest":2,"com.example.financialcore.ApplicationContextTest":1,"com.example.financialcore.audit.AuditPropagationIT":1,"com.example.financialcore.ConcurrencyHarnessTest":4,"com.example.financialcore.CoreSchemaIT":1,"com.example.financialcore.idempotency.AtomicClaim50IT":2,"com.example.financialcore.idempotency.IdempotencySchemaIT":1,"com.example.financialcore.idempotency.RequestHasherTest":2,"com.example.financialcore.ledger.LedgerQueryIT":2,"com.example.financialcore.ledger.LedgerQueryLimitTest":1,"com.example.financialcore.security.CloudFailClosedSecurityIT":1,"com.example.financialcore.security.MaskingTest":2,"com.example.financialcore.security.ObjectAuthorizationIT":2,"com.example.financialcore.security.SecurityStatusContractTest":1,"com.example.financialcore.transfer.api.TransferControllerHappyPathTest":1,"com.example.financialcore.transfer.api.TransferControllerReplayTest":1,"com.example.financialcore.transfer.api.TransferControllerTest":4,"com.example.financialcore.transfer.api.TransferRequestValidationTest":1,"com.example.financialcore.transfer.SortedLockTransferIT":1,"com.example.financialcore.transfer.TransactionPropagationIT":1,"com.example.financialcore.transfer.TransactionProxyIT":1,"com.example.financialcore.transfer.TransferBalanceIT":1,"com.example.financialcore.transfer.TransferFailurePointIT":2,"com.example.financialcore.transfer.TransferIdempotencyIT":1,"com.example.financialcore.transfer.TransferIntegrationTest":9}}
STEP 06 / 13
코드 한 줄씩 한국어로 번역
비어 있지 않은 1줄을 모두 한국어로 옮깁니다.
비어 있지 않은 원본 줄은 하나도 생략하지 않습니다.
| 줄 | 원본 | 한국어 번역 |
|---|---|---|
| 1 | {"selectors":43,"classes":{"com.example.financialcore.account.AccountJpaMappingTest":1,"com.example.financialcore.account.AccountServiceTest":1,"com.example.financialcore.account.AccountTest":5,"com.example.financialcore.account.api.AccountControllerHappyPathTest":1,"com.example.financialcore.account.api.AccountControllerPersistenceIT":1,"com.example.financialcore.account.api.AccountControllerTest":4,"com.example.financialcore.account.api.CreateAccountRequestValidationTest":1,"com.example.financialcore.account.ConcurrentWithdraw20IT":1,"com.example.financialcore.account.LostUpdateBaselineIT":2,"com.example.financialcore.account.OpeningIntegrationTest":1,"com.example.financialcore.account.OptimisticAccountIT":1,"com.example.financialcore.api.ApiExceptionHandlerTest":1,"com.example.financialcore.api.RequestIdFilterTest":2,"com.example.financialcore.ApplicationContextTest":1,"com.example.financialcore.audit.AuditPropagationIT":1,"com.example.financialcore.ConcurrencyHarnessTest":4,"com.example.financialcore.CoreSchemaIT":1,"com.example.financialcore.idempotency.AtomicClaim50IT":2,"com.example.financialcore.idempotency.IdempotencySchemaIT":1,"com.example.financialcore.idempotency.RequestHasherTest":2,"com.example.financialcore.ledger.LedgerQueryIT":2,"com.example.financialcore.ledger.LedgerQueryLimitTest":1,"com.example.financialcore.security.CloudFailClosedSecurityIT":1,"com.example.financialcore.security.MaskingTest":2,"com.example.financialcore.security.ObjectAuthorizationIT":2,"com.example.financialcore.security.SecurityStatusContractTest":1,"com.example.financialcore.transfer.api.TransferControllerHappyPathTest":1,"com.example.financialcore.transfer.api.TransferControllerReplayTest":1,"com.example.financialcore.transfer.api.TransferControllerTest":4,"com.example.financialcore.transfer.api.TransferRequestValidationTest":1,"com.example.financialcore.transfer.SortedLockTransferIT":1,"com.example.financialcore.transfer.TransactionPropagationIT":1,"com.example.financialcore.transfer.TransactionProxyIT":1,"com.example.financialcore.transfer.TransferBalanceIT":1,"com.example.financialcore.transfer.TransferFailurePointIT":2,"com.example.financialcore.transfer.TransferIdempotencyIT":1,"com.example.financialcore.transfer.TransferIntegrationTest":9}} | 실행 의미: selector 총수를 JSON 계약에 고정한다. |
STEP 07 / 13
기존 수준의 한 줄 읽기·문법 해부
쉬운 설명 다음에 문법과 실행 순서를 정밀하게 읽습니다.
한 줄로 읽기core-v1-expected.json — 37개 class·66개 test의 exact 계약는 coreV1Gate가 받아야 할 37개 JUnit class와 class별 test 수, selector 합계 43을 한 JSON 계약으로 고정한다.
문법 해부
- .json 문법에서 선언·조건·pipeline·block 경계를 먼저 나눈다.
- expected 값과 actual 결과를 같은 이름처럼 보여도 서로 다른 source로 읽는다.
- native exit·row count·hash·사람 판정을 서로 대체하지 않는다.
실행 순서
- 입력 경로·fixture·환경변수·expected 계약을 고정한다.
- source가 실행하는 native process·HTTP·SQL 또는 형식 검사를 따라간다.
- actual 값과 exact marker를 대조하고 실패면 성공 발행 전에 중단한다.
- finally cleanup과 비범위를 evidence에 남긴다.
W24 조각별 정밀 해설
F01-C01 · 원문 1–1줄
- 문법 해부
- .json 문법으로 1–1줄의 선언·조건·pipeline·block을 나눈다.
- 실제 값 추적
- selectors=43, classes=37, tests=66를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- expected와 actual이 일치하고 owner evidence가 같은 run/hash에 연결되는 경우다.
- 틀린 예·반례
- 목록 자체는 test 실행 결과가 아니다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- 파일 존재·문자열·hash·exit0 하나를 의미 Green 전체와 같다고 보지 않는다.
- 하지 않는 일
- 목록 자체는 test 실행 결과가 아니다; unexpected class도 별도 검출해야 한다; skip은 성공으로 세지 않는다
- 다음 연결
- 다음 조각 또는 F01 evidence 판정으로 상태를 넘긴다.
실행 순서 — core-v1-expected.json — 37개 class·66개 test의 exact 계약
-
classes=37가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 coreV1Gate가 받아야 할 37개 JUnit class와 class별 test 수, selector 합계 43을 한 JSON 계약으로 고정한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘unexpected class도 별도 검출해야 한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 classes=37와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 08 / 13
실제 값 따라가기
같은 입력값이 어느 줄을 지나 어떤 결과가 되는지 추적합니다.
| 순서 | 들어온 값 | 코드가 하는 일 | 나온 값·상태 | 경계 |
|---|---|---|---|---|
| 입력 | selectors=43 | source 계약에 대입 | F01 실행/설명 시작 상태 | 목록 자체는 test 실행 결과가 아니다 |
| 검증 | classes=37 | expected와 actual 또는 형식 대조 | 통과 또는 첫 mismatch | unexpected class도 별도 검출해야 한다 |
| 증거 | minified one-line JSON | marker·hash·row를 같은 run에 연결 | 범위가 적힌 evidence 후보 | skip은 성공으로 세지 않는다 |
실제 값 — core-v1-expected.json — 37개 class·66개 test의 exact 계약
-
tests=66가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 coreV1Gate가 받아야 할 37개 JUnit class와 class별 test 수, selector 합계 43을 한 JSON 계약으로 고정한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘skip은 성공으로 세지 않는다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 tests=66와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 09 / 13
Gradle·PowerShell·HTTP·PostgreSQL 내부에서 벌어지는 일
Gradle·JUnit XML·PowerShell·HTTP·PostgreSQL·Docker에서 실제로 일어나는 일과 증명 범위를 구분합니다.
core-v1-expected.json bytes와 expected 값을 읽는다.
파일 존재만으로 runtime 성공은 아니다.native exit·HTTP status·JUnit XML·DB row·hash 중 이 파일이 소유한 값을 만든다.
목록 자체는 test 실행 결과가 아니다관련 evidence와 사람 의미 검토를 release 후보에 연결한다.
skip은 성공으로 세지 않는다첫 실패 경계 — core-v1-expected.json — 37개 class·66개 test의 exact 계약
-
minified one-line JSON가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 coreV1Gate가 받아야 할 37개 JUnit class와 class별 test 수, selector 합계 43을 한 JSON 계약으로 고정한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘목록 자체는 test 실행 결과가 아니다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 minified one-line JSON와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 10 / 13
흔한 착각과 틀린 예
그럴듯하지만 틀린 해석을 반례로 고칩니다.
❌ selectors=43 문자열이 source에 있으니 실제 실행도 Green이다.
왜 틀리나 source literal과 runtime 관찰값은 다른 증거다.
바르게 읽기 native exit·actual XML/HTTP/DB evidence를 별도로 확인한다.
반례 script가 실행 전 경로 오류로 멈춰도 literal은 그대로 남는다.
❌ 파일 SHA-256이 있으면 내용의 의미와 사실성도 검증됐다.
왜 틀리나 hash는 동일 bytes만 말한다.
바르게 읽기 schema·수치·질문·근거는 별도 자동 또는 사람 판정을 거친다.
반례 빈 review 질문을 가진 CSV도 안정된 hash를 가진다.
❌ LOCAL_ARTIFACT_VALIDATED는 release Green과 같다.
왜 틀리나 generic validator는 파일 shape만 확인한다.
바르게 읽기 HUMAN_SEMANTIC_REVIEW_REQUIRED를 유지한다.
반례 잘못된 track 점수표도 byte 수 조건은 통과할 수 있다.
❌ 이 파일이 W24 전체 lifecycle을 모두 소유한다.
왜 틀리나 각 source는 Gate·demo·cleanup·사람 review 중 일부만 담당한다.
바르게 읽기 owner와 non-responsibility를 release manifest에서 분리한다.
반례 D4 source audit에는 runtime_claim=false가 명시된다.
❌ 이전 주 Green이나 오래된 log를 현재 commit 결과로 재사용한다.
왜 틀리나 source·commit·actual result가 같은 실행에 묶이지 않는다.
바르게 읽기 release 후보에서 새 evidence와 hash를 만든다.
반례 expected JSON이 바뀌면 예전 XML은 exact inventory를 증명하지 못한다.
STEP 11 / 13
이 코드가 보장하지 않는 것
이 코드가 책임지지 않는 일을 분리합니다.
목록 자체는 test 실행 결과가 아니다
이 책임을 맡는 곳: runtime Gateunexpected class도 별도 검출해야 한다
이 책임을 맡는 곳: external/human reviewskip은 성공으로 세지 않는다
이 책임을 맡는 곳: release manifest목록 자체는 test 실행 결과가 아니다
이 책임을 맡는 곳: 운영 환경증명하지 않는 범위 — core-v1-expected.json — 37개 class·66개 test의 exact 계약
-
selectors=43가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 coreV1Gate가 받아야 할 37개 JUnit class와 class별 test 수, selector 합계 43을 한 JSON 계약으로 고정한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘unexpected class도 별도 검출해야 한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 selectors=43와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 12 / 13
직접 다시 써보기
뜻 → 조각 → 전체 코드 순서로 다시 씁니다.
1단계 · 뜻부터 복원
- coreV1Gate가 받아야 할 37개 JUnit class와 class별 test 수, selector 합계 43을 한 JSON 계약으로 고정한다.
- 핵심 값은 selectors=43, classes=37, tests=66, minified one-line JSON다.
2단계 · 코드 조각 재조립
- 1. selector 총수를 JSON 계약에 고정한다
3단계 · 파일 전체 다시 쓰기
learning_stages/w24/overlay/core-v1-expected.json을 새 파일에 다시 쓰고 expected·actual·실패·cleanup·비범위를 주석으로 표시한다.
자가 점검
- 비어 있지 않은 모든 source 줄을 한 번씩 읽었나?
- source shape와 runtime Green을 분리했나?
- 사람 검토·외부 상태를 자동 성공으로 꾸미지 않았나?
- 첫 실패와 cleanup 책임을 설명할 수 있나?
STEP 13 / 13
전체 원본 source
감사로 고정한 전체 source를 가감 없이 확인합니다.
원문 정본 전체 source 확인하기
{"selectors":43,"classes":{"com.example.financialcore.account.AccountJpaMappingTest":1,"com.example.financialcore.account.AccountServiceTest":1,"com.example.financialcore.account.AccountTest":5,"com.example.financialcore.account.api.AccountControllerHappyPathTest":1,"com.example.financialcore.account.api.AccountControllerPersistenceIT":1,"com.example.financialcore.account.api.AccountControllerTest":4,"com.example.financialcore.account.api.CreateAccountRequestValidationTest":1,"com.example.financialcore.account.ConcurrentWithdraw20IT":1,"com.example.financialcore.account.LostUpdateBaselineIT":2,"com.example.financialcore.account.OpeningIntegrationTest":1,"com.example.financialcore.account.OptimisticAccountIT":1,"com.example.financialcore.api.ApiExceptionHandlerTest":1,"com.example.financialcore.api.RequestIdFilterTest":2,"com.example.financialcore.ApplicationContextTest":1,"com.example.financialcore.audit.AuditPropagationIT":1,"com.example.financialcore.ConcurrencyHarnessTest":4,"com.example.financialcore.CoreSchemaIT":1,"com.example.financialcore.idempotency.AtomicClaim50IT":2,"com.example.financialcore.idempotency.IdempotencySchemaIT":1,"com.example.financialcore.idempotency.RequestHasherTest":2,"com.example.financialcore.ledger.LedgerQueryIT":2,"com.example.financialcore.ledger.LedgerQueryLimitTest":1,"com.example.financialcore.security.CloudFailClosedSecurityIT":1,"com.example.financialcore.security.MaskingTest":2,"com.example.financialcore.security.ObjectAuthorizationIT":2,"com.example.financialcore.security.SecurityStatusContractTest":1,"com.example.financialcore.transfer.api.TransferControllerHappyPathTest":1,"com.example.financialcore.transfer.api.TransferControllerReplayTest":1,"com.example.financialcore.transfer.api.TransferControllerTest":4,"com.example.financialcore.transfer.api.TransferRequestValidationTest":1,"com.example.financialcore.transfer.SortedLockTransferIT":1,"com.example.financialcore.transfer.TransactionPropagationIT":1,"com.example.financialcore.transfer.TransactionProxyIT":1,"com.example.financialcore.transfer.TransferBalanceIT":1,"com.example.financialcore.transfer.TransferFailurePointIT":2,"com.example.financialcore.transfer.TransferIdempotencyIT":1,"com.example.financialcore.transfer.TransferIntegrationTest":9}}
02core-v1-gate.gradle — wildcard 없는 exact Gradle selector
learning_stages/w24/overlay/core-v1-gate.gradle
패키지 정본 보조 계약 · exact Gradle gate bytes · 정본 · W24-F0255줄 연결55줄 번역5 chunks
core-v1-gate.gradle — wildcard 없는 exact Gradle selector
learning_stages/w24/overlay/core-v1-gate.gradle
패키지 정본 보조 계약 · exact Gradle gate bytes · 정본 · W24-F02STEP 01 / 13
오늘 이 코드에서 해결할 문제
무엇을 이해해야 하는지 질문부터 잡습니다.
W5–W12 누적 selector와 W19/W20 production contract를 exact includeTestsMatching 목록으로 coreV1Gate에 연결한다.
- failOnNoMatchingTests=true은 어느 source와 실제 결과에서 확인해야 할까?
- 첫 실패를 만드는 조건과 fail-closed 지점은 어디일까?
- 왜 ‘selector가 보여도 실행 Green은 아니다’를 별도 경계로 남겨야 할까?
failOnNoMatchingTests=true43 selectorsJUnit Platformno wildcard왜 필요한가 — core-v1-gate.gradle — wildcard 없는 exact Gradle selector
-
failOnNoMatchingTests=true가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 W5–W12 누적 selector와 W19/W20 production contract를 exact includeTestsMatching 목록으로 coreV1Gate에 연결한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘selector가 보여도 실행 Green은 아니다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 failOnNoMatchingTests=true와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 02 / 13
아주 짧게: 이 코드는 왜 필요할까?
웹소설 대신 이 코드가 필요한 이유만 두 문단으로 쉽게 봅니다.
새 기능을 멈춘 팀이 코드·test·문서·demo를 같은 release 후보에 묶어 하나씩 검수한다.
검수 도장이 붙은 공통 거래 코어 출고 상자
이 파일은 W5–W12 누적 selector와 W19/W20 production contract를 exact includeTestsMatching 목록으로 coreV1Gate에 연결한다. 눈으로 읽을 때는 각 줄을 검수표 한 칸처럼 보고, 입력과 다음 상태를 놓치지 않는다.
마지막 도장은 source shape와 실제 runtime·사람 검토를 구분한 뒤에만 찍는다. 특히 selector가 보여도 실행 Green은 아니다
딱 여기까지만 비유는 실행 순서를 돕지만 실제 Gradle·Docker·DB·사람 review를 대신하지 않는다.
STEP 03 / 13
초등학생도 이해하는 설명
생활 비유와 실제 코드의 경계를 함께 확인합니다.
값 1: failOnNoMatchingTests=true
이 파일에서 계속 확인할 고정 단서가 failOnNoMatchingTests=true다.
- 코드 연결
F02 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- selector가 보여도 실행 Green은 아니다
값 2: 43 selectors
이 파일에서 계속 확인할 고정 단서가 43 selectors다.
- 코드 연결
F02 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- reference build.gradle의 23-selector coreV1Gate와 learner overlay의 43-selector/37-suite/66-test 계약은 서로 다르다
값 3: JUnit Platform
이 파일에서 계속 확인할 고정 단서가 JUnit Platform다.
- 코드 연결
F02 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- GateOverlay 뒤 서로 다른 LearnerRoot를 검증해야 하며 reference root와 learner root를 같게 두면 안 된다
값 4: no wildcard
이 파일에서 계속 확인할 고정 단서가 no wildcard다.
- 코드 연결
F02 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- XML inventory 검증은 verifier 책임이다
STEP 04 / 13
비유 ↔ 코드 전체 연결표
감사 규칙상 연결 대상인 원본 55줄을 빠짐없이 연결합니다.
| 줄 | 정확한 원본 줄 | STARRY 비유 | 실제 뜻·입력·결과·한계 |
|---|---|---|---|
| 1줄F02-L01 | / |
출고표 1번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 core-v1-gate.gradle의 다음 검증 또는 설명 단계를 구성한다.
|
| 2줄F02-L02 | / |
출고표 2번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 core-v1-gate.gradle의 다음 검증 또는 설명 단계를 구성한다.
|
| 3줄F02-L03 | tasks. |
출고표 3번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 Gradle에 coreV1Gate Test task를 등록한다.
|
| 4줄F02-L04 | group = |
출고표 4번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 core-v1-gate.gradle의 다음 검증 또는 설명 단계를 구성한다.
|
| 5줄F02-L05 | description = |
출고표 5번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 core-v1-gate.gradle의 다음 검증 또는 설명 단계를 구성한다.
|
| 6줄F02-L06 | testClassesDirs = |
출고표 6번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 class 이름과 기대 test 수를 exact inventory로 고정한다.
|
| 7줄F02-L07 | classpath = |
출고표 7번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 core-v1-gate.gradle의 다음 검증 또는 설명 단계를 구성한다.
|
| 8줄F02-L08 | useJUnitPlatform( |
출고표 8번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 core-v1-gate.gradle의 다음 검증 또는 설명 단계를 구성한다.
|
| 9줄F02-L09 | filter { |
출고표 9번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 조건·반복·함수의 실행 block을 연다.
|
| 10줄F02-L10 | failOnNoMatchingTests = |
출고표 10번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 selector가 0개 test를 찾으면 성공 대신 실패하게 한다.
|
| 11줄F02-L11 | includeTestsMatching 'com. |
출고표 11번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 정확한 JUnit class 또는 method selector 하나를 Gate에 추가한다.
|
| 12줄F02-L12 | includeTestsMatching 'com. |
출고표 12번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 정확한 JUnit class 또는 method selector 하나를 Gate에 추가한다.
|
| 13줄F02-L13 | includeTestsMatching 'com. |
출고표 13번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 정확한 JUnit class 또는 method selector 하나를 Gate에 추가한다.
|
| 14줄F02-L14 | includeTestsMatching 'com. |
출고표 14번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 정확한 JUnit class 또는 method selector 하나를 Gate에 추가한다.
|
| 15줄F02-L15 | includeTestsMatching 'com. |
출고표 15번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 정확한 JUnit class 또는 method selector 하나를 Gate에 추가한다.
|
| 16줄F02-L16 | includeTestsMatching 'com. |
출고표 16번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 정확한 JUnit class 또는 method selector 하나를 Gate에 추가한다.
|
| 17줄F02-L17 | includeTestsMatching 'com. |
출고표 17번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 정확한 JUnit class 또는 method selector 하나를 Gate에 추가한다.
|
| 18줄F02-L18 | includeTestsMatching 'com. |
출고표 18번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 정확한 JUnit class 또는 method selector 하나를 Gate에 추가한다.
|
| 19줄F02-L19 | includeTestsMatching 'com. |
출고표 19번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 정확한 JUnit class 또는 method selector 하나를 Gate에 추가한다.
|
| 20줄F02-L20 | includeTestsMatching 'com. |
출고표 20번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 정확한 JUnit class 또는 method selector 하나를 Gate에 추가한다.
|
| 21줄F02-L21 | includeTestsMatching 'com. |
출고표 21번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 정확한 JUnit class 또는 method selector 하나를 Gate에 추가한다.
|
| 22줄F02-L22 | includeTestsMatching 'com. |
출고표 22번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 정확한 JUnit class 또는 method selector 하나를 Gate에 추가한다.
|
| 23줄F02-L23 | includeTestsMatching 'com. |
출고표 23번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 정확한 JUnit class 또는 method selector 하나를 Gate에 추가한다.
|
| 24줄F02-L24 | includeTestsMatching 'com. |
출고표 24번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 정확한 JUnit class 또는 method selector 하나를 Gate에 추가한다.
|
| 25줄F02-L25 | includeTestsMatching 'com. |
출고표 25번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 정확한 JUnit class 또는 method selector 하나를 Gate에 추가한다.
|
| 26줄F02-L26 | includeTestsMatching 'com. |
출고표 26번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 정확한 JUnit class 또는 method selector 하나를 Gate에 추가한다.
|
| 27줄F02-L27 | includeTestsMatching 'com. |
출고표 27번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 정확한 JUnit class 또는 method selector 하나를 Gate에 추가한다.
|
| 28줄F02-L28 | includeTestsMatching 'com. |
출고표 28번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 정확한 JUnit class 또는 method selector 하나를 Gate에 추가한다.
|
| 29줄F02-L29 | includeTestsMatching 'com. |
출고표 29번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 정확한 JUnit class 또는 method selector 하나를 Gate에 추가한다.
|
| 30줄F02-L30 | includeTestsMatching 'com. |
출고표 30번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 정확한 JUnit class 또는 method selector 하나를 Gate에 추가한다.
|
| 31줄F02-L31 | includeTestsMatching 'com. |
출고표 31번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 정확한 JUnit class 또는 method selector 하나를 Gate에 추가한다.
|
| 32줄F02-L32 | includeTestsMatching 'com. |
출고표 32번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 정확한 JUnit class 또는 method selector 하나를 Gate에 추가한다.
|
| 33줄F02-L33 | includeTestsMatching 'com. |
출고표 33번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 정확한 JUnit class 또는 method selector 하나를 Gate에 추가한다.
|
| 34줄F02-L34 | includeTestsMatching 'com. |
출고표 34번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 정확한 JUnit class 또는 method selector 하나를 Gate에 추가한다.
|
| 35줄F02-L35 | includeTestsMatching 'com. |
출고표 35번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 정확한 JUnit class 또는 method selector 하나를 Gate에 추가한다.
|
| 36줄F02-L36 | includeTestsMatching 'com. |
출고표 36번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 정확한 JUnit class 또는 method selector 하나를 Gate에 추가한다.
|
| 37줄F02-L37 | includeTestsMatching 'com. |
출고표 37번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 정확한 JUnit class 또는 method selector 하나를 Gate에 추가한다.
|
| 38줄F02-L38 | includeTestsMatching 'com. |
출고표 38번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 정확한 JUnit class 또는 method selector 하나를 Gate에 추가한다.
|
| 39줄F02-L39 | includeTestsMatching 'com. |
출고표 39번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 정확한 JUnit class 또는 method selector 하나를 Gate에 추가한다.
|
| 40줄F02-L40 | includeTestsMatching 'com. |
출고표 40번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 정확한 JUnit class 또는 method selector 하나를 Gate에 추가한다.
|
| 41줄F02-L41 | includeTestsMatching 'com. |
출고표 41번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 정확한 JUnit class 또는 method selector 하나를 Gate에 추가한다.
|
| 42줄F02-L42 | includeTestsMatching 'com. |
출고표 42번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 정확한 JUnit class 또는 method selector 하나를 Gate에 추가한다.
|
| 43줄F02-L43 | includeTestsMatching 'com. |
출고표 43번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 정확한 JUnit class 또는 method selector 하나를 Gate에 추가한다.
|
| 44줄F02-L44 | includeTestsMatching 'com. |
출고표 44번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 정확한 JUnit class 또는 method selector 하나를 Gate에 추가한다.
|
| 45줄F02-L45 | includeTestsMatching 'com. |
출고표 45번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 정확한 JUnit class 또는 method selector 하나를 Gate에 추가한다.
|
| 46줄F02-L46 | includeTestsMatching 'com. |
출고표 46번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 정확한 JUnit class 또는 method selector 하나를 Gate에 추가한다.
|
| 47줄F02-L47 | includeTestsMatching 'com. |
출고표 47번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 정확한 JUnit class 또는 method selector 하나를 Gate에 추가한다.
|
| 48줄F02-L48 | includeTestsMatching 'com. |
출고표 48번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 정확한 JUnit class 또는 method selector 하나를 Gate에 추가한다.
|
| 49줄F02-L49 | includeTestsMatching 'com. |
출고표 49번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 정확한 JUnit class 또는 method selector 하나를 Gate에 추가한다.
|
| 50줄F02-L50 | includeTestsMatching 'com. |
출고표 50번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 정확한 JUnit class 또는 method selector 하나를 Gate에 추가한다.
|
| 51줄F02-L51 | includeTestsMatching 'com. |
출고표 51번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 정확한 JUnit class 또는 method selector 하나를 Gate에 추가한다.
|
| 52줄F02-L52 | includeTestsMatching 'com. |
출고표 52번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 정확한 JUnit class 또는 method selector 하나를 Gate에 추가한다.
|
| 53줄F02-L53 | includeTestsMatching 'com. |
출고표 53번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 정확한 JUnit class 또는 method selector 하나를 Gate에 추가한다.
|
| 54줄F02-L54 | } |
출고표 54번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 55줄F02-L55 | } |
출고표 55번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
STEP 05 / 13
원본 코드 조각
원본을 5개 의미 조각으로 나누어 그대로 확인합니다.
파일을 한꺼번에 외우지 않고 실행 의미가 이어지는 작은 조각으로 봅니다. 아래 코드는 hash로 고정한 native 정본 source에서 그대로 잘랐습니다.
// W13_W24_LEARNER_CORE_V1_GATE
// Exact union of every W5-W12 staged selector plus six production W19/W20 contracts.
tasks.register('coreV1Gate', Test) {
group = 'verification'
description = 'Exact progressive core V1 release gate; no final-reference-only tests.'
testClassesDirs = sourceSets.test.output.classesDirs
classpath = sourceSets.test.runtimeClasspath
useJUnitPlatform()
filter {
failOnNoMatchingTests = true
includeTestsMatching 'com.example.financialcore.ApplicationContextTest'
includeTestsMatching 'com.example.financialcore.ConcurrencyHarnessTest'
includeTestsMatching 'com.example.financialcore.ConcurrencyHarnessTest.fixed_pool_bounds_observed_activity_and_accounts_for_all_tasks'
includeTestsMatching 'com.example.financialcore.ConcurrencyHarnessTest.ready_timeout_is_a_failure_and_never_a_green_run'
includeTestsMatching 'com.example.financialcore.CoreSchemaIT'
includeTestsMatching 'com.example.financialcore.account.AccountJpaMappingTest'
includeTestsMatching 'com.example.financialcore.account.AccountServiceTest'
includeTestsMatching 'com.example.financialcore.account.AccountTest'
includeTestsMatching 'com.example.financialcore.account.ConcurrentWithdraw20IT'
includeTestsMatching 'com.example.financialcore.account.LostUpdateBaselineIT'
includeTestsMatching 'com.example.financialcore.account.LostUpdateBaselineIT.production_pessimistic_lock_path_commits_twice_and_preserves_both_updates'
includeTestsMatching 'com.example.financialcore.account.LostUpdateBaselineIT.test_only_versionless_unconditional_updates_commit_twice_and_lose_one_update'
includeTestsMatching 'com.example.financialcore.account.OpeningIntegrationTest'
includeTestsMatching 'com.example.financialcore.account.OptimisticAccountIT'
includeTestsMatching 'com.example.financialcore.account.api.AccountControllerHappyPathTest'
includeTestsMatching 'com.example.financialcore.account.api.AccountControllerPersistenceIT'
includeTestsMatching 'com.example.financialcore.account.api.AccountControllerTest'
includeTestsMatching 'com.example.financialcore.account.api.CreateAccountRequestValidationTest'
includeTestsMatching 'com.example.financialcore.api.ApiExceptionHandlerTest'
includeTestsMatching 'com.example.financialcore.api.RequestIdFilterTest'
includeTestsMatching 'com.example.financialcore.audit.AuditPropagationIT'
includeTestsMatching 'com.example.financialcore.idempotency.AtomicClaim50IT'
includeTestsMatching 'com.example.financialcore.idempotency.IdempotencySchemaIT'
includeTestsMatching 'com.example.financialcore.idempotency.RequestHasherTest'
includeTestsMatching 'com.example.financialcore.ledger.LedgerQueryIT'
includeTestsMatching 'com.example.financialcore.ledger.LedgerQueryIT.keysetPagesAreStableAndDoNotRepeatTheCursorRow'
includeTestsMatching 'com.example.financialcore.ledger.LedgerQueryIT.reconciliationReturnsZeroThenDetectsOneInjectedMismatch'
includeTestsMatching 'com.example.financialcore.ledger.LedgerQueryLimitTest'
includeTestsMatching 'com.example.financialcore.security.CloudFailClosedSecurityIT'
includeTestsMatching 'com.example.financialcore.security.MaskingTest'
includeTestsMatching 'com.example.financialcore.security.ObjectAuthorizationIT'
includeTestsMatching 'com.example.financialcore.security.SecurityStatusContractTest'
includeTestsMatching 'com.example.financialcore.transfer.SortedLockTransferIT'
includeTestsMatching 'com.example.financialcore.transfer.TransactionPropagationIT'
includeTestsMatching 'com.example.financialcore.transfer.TransactionProxyIT'
includeTestsMatching 'com.example.financialcore.transfer.TransferBalanceIT'
includeTestsMatching 'com.example.financialcore.transfer.TransferFailurePointIT'
includeTestsMatching 'com.example.financialcore.transfer.TransferIdempotencyIT'
includeTestsMatching 'com.example.financialcore.transfer.TransferIntegrationTest'
includeTestsMatching 'com.example.financialcore.transfer.api.TransferControllerHappyPathTest'
includeTestsMatching 'com.example.financialcore.transfer.api.TransferControllerReplayTest'
includeTestsMatching 'com.example.financialcore.transfer.api.TransferControllerTest'
includeTestsMatching 'com.example.financialcore.transfer.api.TransferRequestValidationTest'
}
}
STEP 06 / 13
코드 한 줄씩 한국어로 번역
비어 있지 않은 55줄을 모두 한국어로 옮깁니다.
비어 있지 않은 원본 줄은 하나도 생략하지 않습니다.
| 줄 | 원본 | 한국어 번역 |
|---|---|---|
| 1 | // W13_W24_LEARNER_CORE_V1_GATE | 실행 의미: core-v1-gate.gradle의 다음 검증 또는 설명 단계를 구성한다. |
| 2 | // Exact union of every W5-W12 staged selector plus six production W19/W20 contracts. | 실행 의미: core-v1-gate.gradle의 다음 검증 또는 설명 단계를 구성한다. |
| 3 | tasks.register('coreV1Gate', Test) { | 실행 의미: Gradle에 coreV1Gate Test task를 등록한다. |
| 4 | group = 'verification' | 실행 의미: core-v1-gate.gradle의 다음 검증 또는 설명 단계를 구성한다. |
| 5 | description = 'Exact progressive core V1 release gate; no final-reference-only tests.' | 실행 의미: core-v1-gate.gradle의 다음 검증 또는 설명 단계를 구성한다. |
| 6 | testClassesDirs = sourceSets.test.output.classesDirs | 실행 의미: class 이름과 기대 test 수를 exact inventory로 고정한다. |
| 7 | classpath = sourceSets.test.runtimeClasspath | 실행 의미: core-v1-gate.gradle의 다음 검증 또는 설명 단계를 구성한다. |
| 8 | useJUnitPlatform() | 실행 의미: core-v1-gate.gradle의 다음 검증 또는 설명 단계를 구성한다. |
| 9 | filter { | 실행 의미: 조건·반복·함수의 실행 block을 연다. |
| 10 | failOnNoMatchingTests = true | 실행 의미: selector가 0개 test를 찾으면 성공 대신 실패하게 한다. |
| 11 | includeTestsMatching 'com.example.financialcore.ApplicationContextTest' | 실행 의미: 정확한 JUnit class 또는 method selector 하나를 Gate에 추가한다. |
| 12 | includeTestsMatching 'com.example.financialcore.ConcurrencyHarnessTest' | 실행 의미: 정확한 JUnit class 또는 method selector 하나를 Gate에 추가한다. |
| 13 | includeTestsMatching 'com.example.financialcore.ConcurrencyHarnessTest.fixed_pool_bounds_observed_activity_and_accounts_for_all_tasks' | 실행 의미: 정확한 JUnit class 또는 method selector 하나를 Gate에 추가한다. |
| 14 | includeTestsMatching 'com.example.financialcore.ConcurrencyHarnessTest.ready_timeout_is_a_failure_and_never_a_green_run' | 실행 의미: 정확한 JUnit class 또는 method selector 하나를 Gate에 추가한다. |
| 15 | includeTestsMatching 'com.example.financialcore.CoreSchemaIT' | 실행 의미: 정확한 JUnit class 또는 method selector 하나를 Gate에 추가한다. |
| 16 | includeTestsMatching 'com.example.financialcore.account.AccountJpaMappingTest' | 실행 의미: 정확한 JUnit class 또는 method selector 하나를 Gate에 추가한다. |
| 17 | includeTestsMatching 'com.example.financialcore.account.AccountServiceTest' | 실행 의미: 정확한 JUnit class 또는 method selector 하나를 Gate에 추가한다. |
| 18 | includeTestsMatching 'com.example.financialcore.account.AccountTest' | 실행 의미: 정확한 JUnit class 또는 method selector 하나를 Gate에 추가한다. |
| 19 | includeTestsMatching 'com.example.financialcore.account.ConcurrentWithdraw20IT' | 실행 의미: 정확한 JUnit class 또는 method selector 하나를 Gate에 추가한다. |
| 20 | includeTestsMatching 'com.example.financialcore.account.LostUpdateBaselineIT' | 실행 의미: 정확한 JUnit class 또는 method selector 하나를 Gate에 추가한다. |
| 21 | includeTestsMatching 'com.example.financialcore.account.LostUpdateBaselineIT.production_pessimistic_lock_path_commits_twice_and_preserves_both_updates' | 실행 의미: 정확한 JUnit class 또는 method selector 하나를 Gate에 추가한다. |
| 22 | includeTestsMatching 'com.example.financialcore.account.LostUpdateBaselineIT.test_only_versionless_unconditional_updates_commit_twice_and_lose_one_update' | 실행 의미: 정확한 JUnit class 또는 method selector 하나를 Gate에 추가한다. |
| 23 | includeTestsMatching 'com.example.financialcore.account.OpeningIntegrationTest' | 실행 의미: 정확한 JUnit class 또는 method selector 하나를 Gate에 추가한다. |
| 24 | includeTestsMatching 'com.example.financialcore.account.OptimisticAccountIT' | 실행 의미: 정확한 JUnit class 또는 method selector 하나를 Gate에 추가한다. |
| 25 | includeTestsMatching 'com.example.financialcore.account.api.AccountControllerHappyPathTest' | 실행 의미: 정확한 JUnit class 또는 method selector 하나를 Gate에 추가한다. |
| 26 | includeTestsMatching 'com.example.financialcore.account.api.AccountControllerPersistenceIT' | 실행 의미: 정확한 JUnit class 또는 method selector 하나를 Gate에 추가한다. |
| 27 | includeTestsMatching 'com.example.financialcore.account.api.AccountControllerTest' | 실행 의미: 정확한 JUnit class 또는 method selector 하나를 Gate에 추가한다. |
| 28 | includeTestsMatching 'com.example.financialcore.account.api.CreateAccountRequestValidationTest' | 실행 의미: 정확한 JUnit class 또는 method selector 하나를 Gate에 추가한다. |
| 29 | includeTestsMatching 'com.example.financialcore.api.ApiExceptionHandlerTest' | 실행 의미: 정확한 JUnit class 또는 method selector 하나를 Gate에 추가한다. |
| 30 | includeTestsMatching 'com.example.financialcore.api.RequestIdFilterTest' | 실행 의미: 정확한 JUnit class 또는 method selector 하나를 Gate에 추가한다. |
| 31 | includeTestsMatching 'com.example.financialcore.audit.AuditPropagationIT' | 실행 의미: 정확한 JUnit class 또는 method selector 하나를 Gate에 추가한다. |
| 32 | includeTestsMatching 'com.example.financialcore.idempotency.AtomicClaim50IT' | 실행 의미: 정확한 JUnit class 또는 method selector 하나를 Gate에 추가한다. |
| 33 | includeTestsMatching 'com.example.financialcore.idempotency.IdempotencySchemaIT' | 실행 의미: 정확한 JUnit class 또는 method selector 하나를 Gate에 추가한다. |
| 34 | includeTestsMatching 'com.example.financialcore.idempotency.RequestHasherTest' | 실행 의미: 정확한 JUnit class 또는 method selector 하나를 Gate에 추가한다. |
| 35 | includeTestsMatching 'com.example.financialcore.ledger.LedgerQueryIT' | 실행 의미: 정확한 JUnit class 또는 method selector 하나를 Gate에 추가한다. |
| 36 | includeTestsMatching 'com.example.financialcore.ledger.LedgerQueryIT.keysetPagesAreStableAndDoNotRepeatTheCursorRow' | 실행 의미: 정확한 JUnit class 또는 method selector 하나를 Gate에 추가한다. |
| 37 | includeTestsMatching 'com.example.financialcore.ledger.LedgerQueryIT.reconciliationReturnsZeroThenDetectsOneInjectedMismatch' | 실행 의미: 정확한 JUnit class 또는 method selector 하나를 Gate에 추가한다. |
| 38 | includeTestsMatching 'com.example.financialcore.ledger.LedgerQueryLimitTest' | 실행 의미: 정확한 JUnit class 또는 method selector 하나를 Gate에 추가한다. |
| 39 | includeTestsMatching 'com.example.financialcore.security.CloudFailClosedSecurityIT' | 실행 의미: 정확한 JUnit class 또는 method selector 하나를 Gate에 추가한다. |
| 40 | includeTestsMatching 'com.example.financialcore.security.MaskingTest' | 실행 의미: 정확한 JUnit class 또는 method selector 하나를 Gate에 추가한다. |
| 41 | includeTestsMatching 'com.example.financialcore.security.ObjectAuthorizationIT' | 실행 의미: 정확한 JUnit class 또는 method selector 하나를 Gate에 추가한다. |
| 42 | includeTestsMatching 'com.example.financialcore.security.SecurityStatusContractTest' | 실행 의미: 정확한 JUnit class 또는 method selector 하나를 Gate에 추가한다. |
| 43 | includeTestsMatching 'com.example.financialcore.transfer.SortedLockTransferIT' | 실행 의미: 정확한 JUnit class 또는 method selector 하나를 Gate에 추가한다. |
| 44 | includeTestsMatching 'com.example.financialcore.transfer.TransactionPropagationIT' | 실행 의미: 정확한 JUnit class 또는 method selector 하나를 Gate에 추가한다. |
| 45 | includeTestsMatching 'com.example.financialcore.transfer.TransactionProxyIT' | 실행 의미: 정확한 JUnit class 또는 method selector 하나를 Gate에 추가한다. |
| 46 | includeTestsMatching 'com.example.financialcore.transfer.TransferBalanceIT' | 실행 의미: 정확한 JUnit class 또는 method selector 하나를 Gate에 추가한다. |
| 47 | includeTestsMatching 'com.example.financialcore.transfer.TransferFailurePointIT' | 실행 의미: 정확한 JUnit class 또는 method selector 하나를 Gate에 추가한다. |
| 48 | includeTestsMatching 'com.example.financialcore.transfer.TransferIdempotencyIT' | 실행 의미: 정확한 JUnit class 또는 method selector 하나를 Gate에 추가한다. |
| 49 | includeTestsMatching 'com.example.financialcore.transfer.TransferIntegrationTest' | 실행 의미: 정확한 JUnit class 또는 method selector 하나를 Gate에 추가한다. |
| 50 | includeTestsMatching 'com.example.financialcore.transfer.api.TransferControllerHappyPathTest' | 실행 의미: 정확한 JUnit class 또는 method selector 하나를 Gate에 추가한다. |
| 51 | includeTestsMatching 'com.example.financialcore.transfer.api.TransferControllerReplayTest' | 실행 의미: 정확한 JUnit class 또는 method selector 하나를 Gate에 추가한다. |
| 52 | includeTestsMatching 'com.example.financialcore.transfer.api.TransferControllerTest' | 실행 의미: 정확한 JUnit class 또는 method selector 하나를 Gate에 추가한다. |
| 53 | includeTestsMatching 'com.example.financialcore.transfer.api.TransferRequestValidationTest' | 실행 의미: 정확한 JUnit class 또는 method selector 하나를 Gate에 추가한다. |
| 54 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 55 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
STEP 07 / 13
기존 수준의 한 줄 읽기·문법 해부
쉬운 설명 다음에 문법과 실행 순서를 정밀하게 읽습니다.
한 줄로 읽기core-v1-gate.gradle — wildcard 없는 exact Gradle selector는 W5–W12 누적 selector와 W19/W20 production contract를 exact includeTestsMatching 목록으로 coreV1Gate에 연결한다.
문법 해부
- .gradle 문법에서 선언·조건·pipeline·block 경계를 먼저 나눈다.
- expected 값과 actual 결과를 같은 이름처럼 보여도 서로 다른 source로 읽는다.
- native exit·row count·hash·사람 판정을 서로 대체하지 않는다.
실행 순서
- 입력 경로·fixture·환경변수·expected 계약을 고정한다.
- source가 실행하는 native process·HTTP·SQL 또는 형식 검사를 따라간다.
- actual 값과 exact marker를 대조하고 실패면 성공 발행 전에 중단한다.
- finally cleanup과 비범위를 evidence에 남긴다.
W24 조각별 정밀 해설
F02-C01 · 원문 1–12줄
- 문법 해부
- .gradle 문법으로 1–12줄의 선언·조건·pipeline·block을 나눈다.
- 실제 값 추적
- failOnNoMatchingTests=true, 43 selectors, JUnit Platform를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- expected와 actual이 일치하고 owner evidence가 같은 run/hash에 연결되는 경우다.
- 틀린 예·반례
- selector가 보여도 실행 Green은 아니다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- 파일 존재·문자열·hash·exit0 하나를 의미 Green 전체와 같다고 보지 않는다.
- 하지 않는 일
- selector가 보여도 실행 Green은 아니다; reference build.gradle의 23-selector coreV1Gate와 learner overlay의 43-selector/37-suite/66-test 계약은 서로 다르다; GateOverlay 뒤 서로 다른 LearnerRoot를 검증해야 하며 reference root와 learner root를 같게 두면 안 된다; XML inventory 검증은 verifier 책임이다
- 다음 연결
- 다음 조각 또는 F02 evidence 판정으로 상태를 넘긴다.
F02-C02 · 원문 13–24줄
- 문법 해부
- .gradle 문법으로 13–24줄의 선언·조건·pipeline·block을 나눈다.
- 실제 값 추적
- failOnNoMatchingTests=true, 43 selectors, JUnit Platform를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- expected와 actual이 일치하고 owner evidence가 같은 run/hash에 연결되는 경우다.
- 틀린 예·반례
- selector가 보여도 실행 Green은 아니다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- 파일 존재·문자열·hash·exit0 하나를 의미 Green 전체와 같다고 보지 않는다.
- 하지 않는 일
- selector가 보여도 실행 Green은 아니다; reference build.gradle의 23-selector coreV1Gate와 learner overlay의 43-selector/37-suite/66-test 계약은 서로 다르다; GateOverlay 뒤 서로 다른 LearnerRoot를 검증해야 하며 reference root와 learner root를 같게 두면 안 된다; XML inventory 검증은 verifier 책임이다
- 다음 연결
- 다음 조각 또는 F02 evidence 판정으로 상태를 넘긴다.
F02-C03 · 원문 25–36줄
- 문법 해부
- .gradle 문법으로 25–36줄의 선언·조건·pipeline·block을 나눈다.
- 실제 값 추적
- failOnNoMatchingTests=true, 43 selectors, JUnit Platform를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- expected와 actual이 일치하고 owner evidence가 같은 run/hash에 연결되는 경우다.
- 틀린 예·반례
- selector가 보여도 실행 Green은 아니다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- 파일 존재·문자열·hash·exit0 하나를 의미 Green 전체와 같다고 보지 않는다.
- 하지 않는 일
- selector가 보여도 실행 Green은 아니다; reference build.gradle의 23-selector coreV1Gate와 learner overlay의 43-selector/37-suite/66-test 계약은 서로 다르다; GateOverlay 뒤 서로 다른 LearnerRoot를 검증해야 하며 reference root와 learner root를 같게 두면 안 된다; XML inventory 검증은 verifier 책임이다
- 다음 연결
- 다음 조각 또는 F02 evidence 판정으로 상태를 넘긴다.
F02-C04 · 원문 37–48줄
- 문법 해부
- .gradle 문법으로 37–48줄의 선언·조건·pipeline·block을 나눈다.
- 실제 값 추적
- failOnNoMatchingTests=true, 43 selectors, JUnit Platform를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- expected와 actual이 일치하고 owner evidence가 같은 run/hash에 연결되는 경우다.
- 틀린 예·반례
- selector가 보여도 실행 Green은 아니다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- 파일 존재·문자열·hash·exit0 하나를 의미 Green 전체와 같다고 보지 않는다.
- 하지 않는 일
- selector가 보여도 실행 Green은 아니다; reference build.gradle의 23-selector coreV1Gate와 learner overlay의 43-selector/37-suite/66-test 계약은 서로 다르다; GateOverlay 뒤 서로 다른 LearnerRoot를 검증해야 하며 reference root와 learner root를 같게 두면 안 된다; XML inventory 검증은 verifier 책임이다
- 다음 연결
- 다음 조각 또는 F02 evidence 판정으로 상태를 넘긴다.
F02-C05 · 원문 49–55줄
- 문법 해부
- .gradle 문법으로 49–55줄의 선언·조건·pipeline·block을 나눈다.
- 실제 값 추적
- failOnNoMatchingTests=true, 43 selectors, JUnit Platform를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- expected와 actual이 일치하고 owner evidence가 같은 run/hash에 연결되는 경우다.
- 틀린 예·반례
- selector가 보여도 실행 Green은 아니다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- 파일 존재·문자열·hash·exit0 하나를 의미 Green 전체와 같다고 보지 않는다.
- 하지 않는 일
- selector가 보여도 실행 Green은 아니다; reference build.gradle의 23-selector coreV1Gate와 learner overlay의 43-selector/37-suite/66-test 계약은 서로 다르다; GateOverlay 뒤 서로 다른 LearnerRoot를 검증해야 하며 reference root와 learner root를 같게 두면 안 된다; XML inventory 검증은 verifier 책임이다
- 다음 연결
- 다음 조각 또는 F02 evidence 판정으로 상태를 넘긴다.
실행 순서 — core-v1-gate.gradle — wildcard 없는 exact Gradle selector
-
43 selectors가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 W5–W12 누적 selector와 W19/W20 production contract를 exact includeTestsMatching 목록으로 coreV1Gate에 연결한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘reference build.gradle의 23-selector coreV1Gate와 learner overlay의 43-selector/37-suite/66-test 계약은 서로 다르다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 43 selectors와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 08 / 13
실제 값 따라가기
같은 입력값이 어느 줄을 지나 어떤 결과가 되는지 추적합니다.
| 순서 | 들어온 값 | 코드가 하는 일 | 나온 값·상태 | 경계 |
|---|---|---|---|---|
| 입력 | failOnNoMatchingTests=true | source 계약에 대입 | F02 실행/설명 시작 상태 | selector가 보여도 실행 Green은 아니다 |
| 검증 | 43 selectors | expected와 actual 또는 형식 대조 | 통과 또는 첫 mismatch | reference build.gradle의 23-selector coreV1Gate와 learner overlay의 43-selector/37-suite/66-test 계약은 서로 다르다 |
| 증거 | no wildcard | marker·hash·row를 같은 run에 연결 | 범위가 적힌 evidence 후보 | XML inventory 검증은 verifier 책임이다 |
실제 값 — core-v1-gate.gradle — wildcard 없는 exact Gradle selector
-
JUnit Platform가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 W5–W12 누적 selector와 W19/W20 production contract를 exact includeTestsMatching 목록으로 coreV1Gate에 연결한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘GateOverlay 뒤 서로 다른 LearnerRoot를 검증해야 하며 reference root와 learner root를 같게 두면 안 된다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 JUnit Platform와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 09 / 13
Gradle·PowerShell·HTTP·PostgreSQL 내부에서 벌어지는 일
Gradle·JUnit XML·PowerShell·HTTP·PostgreSQL·Docker에서 실제로 일어나는 일과 증명 범위를 구분합니다.
core-v1-gate.gradle bytes와 expected 값을 읽는다.
파일 존재만으로 runtime 성공은 아니다.native exit·HTTP status·JUnit XML·DB row·hash 중 이 파일이 소유한 값을 만든다.
selector가 보여도 실행 Green은 아니다관련 evidence와 사람 의미 검토를 release 후보에 연결한다.
XML inventory 검증은 verifier 책임이다첫 실패 경계 — core-v1-gate.gradle — wildcard 없는 exact Gradle selector
-
no wildcard가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 W5–W12 누적 selector와 W19/W20 production contract를 exact includeTestsMatching 목록으로 coreV1Gate에 연결한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘XML inventory 검증은 verifier 책임이다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 no wildcard와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 10 / 13
흔한 착각과 틀린 예
그럴듯하지만 틀린 해석을 반례로 고칩니다.
❌ failOnNoMatchingTests=true 문자열이 source에 있으니 실제 실행도 Green이다.
왜 틀리나 source literal과 runtime 관찰값은 다른 증거다.
바르게 읽기 native exit·actual XML/HTTP/DB evidence를 별도로 확인한다.
반례 script가 실행 전 경로 오류로 멈춰도 literal은 그대로 남는다.
❌ 파일 SHA-256이 있으면 내용의 의미와 사실성도 검증됐다.
왜 틀리나 hash는 동일 bytes만 말한다.
바르게 읽기 schema·수치·질문·근거는 별도 자동 또는 사람 판정을 거친다.
반례 빈 review 질문을 가진 CSV도 안정된 hash를 가진다.
❌ LOCAL_ARTIFACT_VALIDATED는 release Green과 같다.
왜 틀리나 generic validator는 파일 shape만 확인한다.
바르게 읽기 HUMAN_SEMANTIC_REVIEW_REQUIRED를 유지한다.
반례 잘못된 track 점수표도 byte 수 조건은 통과할 수 있다.
❌ 이 파일이 W24 전체 lifecycle을 모두 소유한다.
왜 틀리나 각 source는 Gate·demo·cleanup·사람 review 중 일부만 담당한다.
바르게 읽기 owner와 non-responsibility를 release manifest에서 분리한다.
반례 D4 source audit에는 runtime_claim=false가 명시된다.
❌ 이전 주 Green이나 오래된 log를 현재 commit 결과로 재사용한다.
왜 틀리나 source·commit·actual result가 같은 실행에 묶이지 않는다.
바르게 읽기 release 후보에서 새 evidence와 hash를 만든다.
반례 expected JSON이 바뀌면 예전 XML은 exact inventory를 증명하지 못한다.
STEP 11 / 13
이 코드가 보장하지 않는 것
이 코드가 책임지지 않는 일을 분리합니다.
selector가 보여도 실행 Green은 아니다
이 책임을 맡는 곳: runtime Gatereference build.gradle의 23-selector coreV1Gate와 learner overlay의 43-selector/37-suite/66-test 계약은 서로 다르다
이 책임을 맡는 곳: external/human reviewGateOverlay 뒤 서로 다른 LearnerRoot를 검증해야 하며 reference root와 learner root를 같게 두면 안 된다
이 책임을 맡는 곳: release manifestXML inventory 검증은 verifier 책임이다
이 책임을 맡는 곳: 운영 환경증명하지 않는 범위 — core-v1-gate.gradle — wildcard 없는 exact Gradle selector
-
failOnNoMatchingTests=true가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 W5–W12 누적 selector와 W19/W20 production contract를 exact includeTestsMatching 목록으로 coreV1Gate에 연결한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘selector가 보여도 실행 Green은 아니다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 failOnNoMatchingTests=true와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 12 / 13
직접 다시 써보기
뜻 → 조각 → 전체 코드 순서로 다시 씁니다.
1단계 · 뜻부터 복원
- W5–W12 누적 selector와 W19/W20 production contract를 exact includeTestsMatching 목록으로 coreV1Gate에 연결한다.
- 핵심 값은 failOnNoMatchingTests=true, 43 selectors, JUnit Platform, no wildcard다.
2단계 · 코드 조각 재조립
- 1. core-v1-gate.gradle의 다음 검증 또는 설명 단계를 구성한다
- 2. core-v1-gate.gradle의 다음 검증 또는 설명 단계를 구성한다
- 3. Gradle에 coreV1Gate Test task를 등록한다
- 4. core-v1-gate.gradle의 다음 검증 또는 설명 단계를 구성한다
- 5. core-v1-gate.gradle의 다음 검증 또는 설명 단계를 구성한다
- 6. class 이름과 기대 test 수를 exact inventory로 고정한다
- 7. core-v1-gate.gradle의 다음 검증 또는 설명 단계를 구성한다
- 8. core-v1-gate.gradle의 다음 검증 또는 설명 단계를 구성한다
3단계 · 파일 전체 다시 쓰기
learning_stages/w24/overlay/core-v1-gate.gradle을 새 파일에 다시 쓰고 expected·actual·실패·cleanup·비범위를 주석으로 표시한다.
자가 점검
- 비어 있지 않은 모든 source 줄을 한 번씩 읽었나?
- source shape와 runtime Green을 분리했나?
- 사람 검토·외부 상태를 자동 성공으로 꾸미지 않았나?
- 첫 실패와 cleanup 책임을 설명할 수 있나?
STEP 13 / 13
전체 원본 source
감사로 고정한 전체 source를 가감 없이 확인합니다.
원문 정본 전체 source 확인하기
// W13_W24_LEARNER_CORE_V1_GATE
// Exact union of every W5-W12 staged selector plus six production W19/W20 contracts.
tasks.register('coreV1Gate', Test) {
group = 'verification'
description = 'Exact progressive core V1 release gate; no final-reference-only tests.'
testClassesDirs = sourceSets.test.output.classesDirs
classpath = sourceSets.test.runtimeClasspath
useJUnitPlatform()
filter {
failOnNoMatchingTests = true
includeTestsMatching 'com.example.financialcore.ApplicationContextTest'
includeTestsMatching 'com.example.financialcore.ConcurrencyHarnessTest'
includeTestsMatching 'com.example.financialcore.ConcurrencyHarnessTest.fixed_pool_bounds_observed_activity_and_accounts_for_all_tasks'
includeTestsMatching 'com.example.financialcore.ConcurrencyHarnessTest.ready_timeout_is_a_failure_and_never_a_green_run'
includeTestsMatching 'com.example.financialcore.CoreSchemaIT'
includeTestsMatching 'com.example.financialcore.account.AccountJpaMappingTest'
includeTestsMatching 'com.example.financialcore.account.AccountServiceTest'
includeTestsMatching 'com.example.financialcore.account.AccountTest'
includeTestsMatching 'com.example.financialcore.account.ConcurrentWithdraw20IT'
includeTestsMatching 'com.example.financialcore.account.LostUpdateBaselineIT'
includeTestsMatching 'com.example.financialcore.account.LostUpdateBaselineIT.production_pessimistic_lock_path_commits_twice_and_preserves_both_updates'
includeTestsMatching 'com.example.financialcore.account.LostUpdateBaselineIT.test_only_versionless_unconditional_updates_commit_twice_and_lose_one_update'
includeTestsMatching 'com.example.financialcore.account.OpeningIntegrationTest'
includeTestsMatching 'com.example.financialcore.account.OptimisticAccountIT'
includeTestsMatching 'com.example.financialcore.account.api.AccountControllerHappyPathTest'
includeTestsMatching 'com.example.financialcore.account.api.AccountControllerPersistenceIT'
includeTestsMatching 'com.example.financialcore.account.api.AccountControllerTest'
includeTestsMatching 'com.example.financialcore.account.api.CreateAccountRequestValidationTest'
includeTestsMatching 'com.example.financialcore.api.ApiExceptionHandlerTest'
includeTestsMatching 'com.example.financialcore.api.RequestIdFilterTest'
includeTestsMatching 'com.example.financialcore.audit.AuditPropagationIT'
includeTestsMatching 'com.example.financialcore.idempotency.AtomicClaim50IT'
includeTestsMatching 'com.example.financialcore.idempotency.IdempotencySchemaIT'
includeTestsMatching 'com.example.financialcore.idempotency.RequestHasherTest'
includeTestsMatching 'com.example.financialcore.ledger.LedgerQueryIT'
includeTestsMatching 'com.example.financialcore.ledger.LedgerQueryIT.keysetPagesAreStableAndDoNotRepeatTheCursorRow'
includeTestsMatching 'com.example.financialcore.ledger.LedgerQueryIT.reconciliationReturnsZeroThenDetectsOneInjectedMismatch'
includeTestsMatching 'com.example.financialcore.ledger.LedgerQueryLimitTest'
includeTestsMatching 'com.example.financialcore.security.CloudFailClosedSecurityIT'
includeTestsMatching 'com.example.financialcore.security.MaskingTest'
includeTestsMatching 'com.example.financialcore.security.ObjectAuthorizationIT'
includeTestsMatching 'com.example.financialcore.security.SecurityStatusContractTest'
includeTestsMatching 'com.example.financialcore.transfer.SortedLockTransferIT'
includeTestsMatching 'com.example.financialcore.transfer.TransactionPropagationIT'
includeTestsMatching 'com.example.financialcore.transfer.TransactionProxyIT'
includeTestsMatching 'com.example.financialcore.transfer.TransferBalanceIT'
includeTestsMatching 'com.example.financialcore.transfer.TransferFailurePointIT'
includeTestsMatching 'com.example.financialcore.transfer.TransferIdempotencyIT'
includeTestsMatching 'com.example.financialcore.transfer.TransferIntegrationTest'
includeTestsMatching 'com.example.financialcore.transfer.api.TransferControllerHappyPathTest'
includeTestsMatching 'com.example.financialcore.transfer.api.TransferControllerReplayTest'
includeTestsMatching 'com.example.financialcore.transfer.api.TransferControllerTest'
includeTestsMatching 'com.example.financialcore.transfer.api.TransferRequestValidationTest'
}
}
03verify-core-v1-gate.ps1 — actual XML 37/66을 fail-closed 검증
scripts/verify-core-v1-gate.ps1
PDF 전문 정본 · packaged PowerShell source · 정본 · W24-F0361줄 연결61줄 번역6 chunks
verify-core-v1-gate.ps1 — actual XML 37/66을 fail-closed 검증
scripts/verify-core-v1-gate.ps1
PDF 전문 정본 · packaged PowerShell source · 정본 · W24-F03STEP 01 / 13
오늘 이 코드에서 해결할 문제
무엇을 이해해야 하는지 질문부터 잡습니다.
native Gradle exit, JUnit XML 존재, exact class set, class별 test 수와 failure/error/skip 0을 함께 확인한다.
- CORE_V1_GATE_GREEN은 어느 source와 실제 결과에서 확인해야 할까?
- 첫 실패를 만드는 조건과 fail-closed 지점은 어디일까?
- 왜 ‘XML이 없으면 즉시 실패한다’를 별도 경계로 남겨야 할까?
CORE_V1_GATE_GREENclasses=37tests=66failures/errors/skipped=0왜 필요한가 — 66을 fail-closed 검증
-
CORE_V1_GATE_GREEN가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 native Gradle exit, JUnit XML 존재, exact class set, class별 test 수와 failure/error/skip 0을 함께 확인한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘XML이 없으면 즉시 실패한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 CORE_V1_GATE_GREEN와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 02 / 13
아주 짧게: 이 코드는 왜 필요할까?
웹소설 대신 이 코드가 필요한 이유만 두 문단으로 쉽게 봅니다.
새 기능을 멈춘 팀이 코드·test·문서·demo를 같은 release 후보에 묶어 하나씩 검수한다.
검수 도장이 붙은 공통 거래 코어 출고 상자
이 파일은 native Gradle exit, JUnit XML 존재, exact class set, class별 test 수와 failure/error/skip 0을 함께 확인한다. 눈으로 읽을 때는 각 줄을 검수표 한 칸처럼 보고, 입력과 다음 상태를 놓치지 않는다.
마지막 도장은 source shape와 실제 runtime·사람 검토를 구분한 뒤에만 찍는다. 특히 XML이 없으면 즉시 실패한다
딱 여기까지만 비유는 실행 순서를 돕지만 실제 Gradle·Docker·DB·사람 review를 대신하지 않는다.
STEP 03 / 13
초등학생도 이해하는 설명
생활 비유와 실제 코드의 경계를 함께 확인합니다.
값 1: CORE_V1_GATE_GREEN
이 파일에서 계속 확인할 고정 단서가 CORE_V1_GATE_GREEN다.
- 코드 연결
F03 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- XML이 없으면 즉시 실패한다
값 2: classes=37
이 파일에서 계속 확인할 고정 단서가 classes=37다.
- 코드 연결
F03 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- wildcard·0 tests 성공을 허용하지 않는다
값 3: tests=66
이 파일에서 계속 확인할 고정 단서가 tests=66다.
- 코드 연결
F03 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- 이 HTML은 runner를 실행하지 않았다
값 4: failures/errors/skipped=0
이 파일에서 계속 확인할 고정 단서가 failures/errors/skipped=0다.
- 코드 연결
F03 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- XML이 없으면 즉시 실패한다
STEP 04 / 13
비유 ↔ 코드 전체 연결표
감사 규칙상 연결 대상인 원본 61줄을 빠짐없이 연결합니다.
| 줄 | 정확한 원본 줄 | STARRY 비유 | 실제 뜻·입력·결과·한계 |
|---|---|---|---|
| 1줄F03-L01 | param( |
출고표 1번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 PowerShell script가 받을 입력 계약을 연다.
|
| 2줄F03-L02 | [ |
출고표 2번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 이 인자가 빠지면 실행 시작 전에 binding을 거절한다.
|
| 3줄F03-L03 | [ |
출고표 3번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 이 인자가 빠지면 실행 시작 전에 binding을 거절한다.
|
| 4줄F03-L04 | [ |
출고표 4번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 verify-core-v1-gate.ps1의 다음 검증 또는 설명 단계를 구성한다.
|
| 5줄F03-L05 | ) |
출고표 5번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 7줄F03-L07 | $ErrorActionPreference = |
출고표 7번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 PowerShell 오류를 계속 진행하지 않고 중단시키는 기본 정책을 둔다.
|
| 8줄F03-L08 | $reference = |
출고표 8번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 9줄F03-L09 | $project = |
출고표 9번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 입력 경로를 실제 절대 경로로 확인한다.
|
| 10줄F03-L10 | if ( |
출고표 10번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 조건·반복·함수의 실행 block을 연다.
|
| 11줄F03-L11 | $ExpectedPath = |
출고표 11번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 12줄F03-L12 | } |
출고표 12번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 13줄F03-L13 | $contract = |
출고표 13번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 JSON text를 필드로 접근 가능한 PowerShell object로 바꾼다.
|
| 14줄F03-L14 | $expected = |
출고표 14번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 class 이름과 기대 test 수를 exact inventory로 고정한다.
|
| 15줄F03-L15 | Push-Location $project |
출고표 15번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 verify-core-v1-gate.ps1의 다음 검증 또는 설명 단계를 구성한다.
|
| 16줄F03-L16 | try { |
출고표 16번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 조건·반복·함수의 실행 block을 연다.
|
| 17줄F03-L17 | & . |
출고표 17번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 learner project의 Gradle wrapper로 지정 task를 실행한다.
|
| 18줄F03-L18 | if ( |
출고표 18번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 native process 종료 코드를 검사해 실패를 놓치지 않는다.
|
| 20줄F03-L20 | $resultDirectory = |
출고표 20번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 21줄F03-L21 | $xmlFiles = |
출고표 21번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 JUnit XML 결과 파일만 exact inventory 입력으로 모은다.
|
| 22줄F03-L22 | if ( |
출고표 22번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 24줄F03-L24 | $rows = |
출고표 24번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 고정 목록의 각 항목에 같은 검사를 반복 적용한다.
|
| 25줄F03-L25 | [ |
출고표 25번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 verify-core-v1-gate.ps1의 다음 검증 또는 설명 단계를 구성한다.
|
| 26줄F03-L26 | [ |
출고표 26번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 조건·반복·함수의 실행 block을 연다.
|
| 27줄F03-L27 | class = |
출고표 27번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 JUnit suite의 class 이름과 test/failure/error/skip 수를 읽는다.
|
| 28줄F03-L28 | tests = |
출고표 28번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 JUnit suite의 class 이름과 test/failure/error/skip 수를 읽는다.
|
| 29줄F03-L29 | failures = |
출고표 29번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 JUnit suite의 class 이름과 test/failure/error/skip 수를 읽는다.
|
| 30줄F03-L30 | errors = |
출고표 30번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 JUnit suite의 class 이름과 test/failure/error/skip 수를 읽는다.
|
| 31줄F03-L31 | skipped = |
출고표 31번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 JUnit suite의 class 이름과 test/failure/error/skip 수를 읽는다.
|
| 32줄F03-L32 | } |
출고표 32번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 33줄F03-L33 | } |
출고표 33번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 34줄F03-L34 | $actual = |
출고표 34번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 Markdown 표 또는 PowerShell pipeline에서 값을 열이나 다음 명령으로 연결한다.
|
| 35줄F03-L35 | $missing = |
출고표 35번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 조건을 만족하는 row만 필터링한다.
|
| 36줄F03-L36 | $unexpected = |
출고표 36번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 조건을 만족하는 row만 필터링한다.
|
| 37줄F03-L37 | if ( |
출고표 37번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 조건·반복·함수의 실행 block을 연다.
|
| 38줄F03-L38 | throw "class inventory mismatch; |
출고표 38번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 39줄F03-L39 | } |
출고표 39번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 40줄F03-L40 | $tests = |
출고표 40번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 suite별 수치를 전체 합계로 계산한다.
|
| 41줄F03-L41 | $failures = |
출고표 41번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 suite별 수치를 전체 합계로 계산한다.
|
| 42줄F03-L42 | $errors = |
출고표 42번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 suite별 수치를 전체 합계로 계산한다.
|
| 43줄F03-L43 | $skipped = |
출고표 43번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 suite별 수치를 전체 합계로 계산한다.
|
| 44줄F03-L44 | $wrongCounts = |
출고표 44번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 class 이름과 기대 test 수를 exact inventory로 고정한다.
|
| 45줄F03-L45 | if ( |
출고표 45번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 조건·반복·함수의 실행 block을 연다.
|
| 46줄F03-L46 | throw "test summary is not Green: |
출고표 46번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 47줄F03-L47 | } |
출고표 47번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 49줄F03-L49 | $summary = |
출고표 49번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 50줄F03-L50 | 'CORE_V1_GATE_GREEN', |
출고표 50번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 37 class·66 test·실패/오류/skip 0일 때만 exact local marker를 낸다.
|
| 51줄F03-L51 | "classes= |
출고표 51번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 class 이름과 기대 test 수를 exact inventory로 고정한다.
|
| 52줄F03-L52 | "tests= |
출고표 52번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 verify-core-v1-gate.ps1의 다음 검증 또는 설명 단계를 구성한다.
|
| 53줄F03-L53 | "failures= |
출고표 53번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 verify-core-v1-gate.ps1의 다음 검증 또는 설명 단계를 구성한다.
|
| 54줄F03-L54 | "errors= |
출고표 54번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 verify-core-v1-gate.ps1의 다음 검증 또는 설명 단계를 구성한다.
|
| 55줄F03-L55 | "skipped= |
출고표 55번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 verify-core-v1-gate.ps1의 다음 검증 또는 설명 단계를 구성한다.
|
| 56줄F03-L56 | ) |
출고표 56번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 57줄F03-L57 | $summary |
출고표 57번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 verify-core-v1-gate.ps1의 다음 검증 또는 설명 단계를 구성한다.
|
| 58줄F03-L58 | $parent = |
출고표 58번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 59줄F03-L59 | if ( |
출고표 59번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 조건·반복·함수의 실행 block을 연다.
|
| 60줄F03-L60 | New-Item -ItemType Directory -Force -Path $parent | Out-Null |
출고표 60번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 Markdown 표 또는 PowerShell pipeline에서 값을 열이나 다음 명령으로 연결한다.
|
| 61줄F03-L61 | } |
출고표 61번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 62줄F03-L62 | $summary | Set-Content -LiteralPath $EvidencePath -Encoding utf8 |
출고표 62번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 Markdown 표 또는 PowerShell pipeline에서 값을 열이나 다음 명령으로 연결한다.
|
| 63줄F03-L63 | } finally { |
출고표 63번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 중간 실패가 있어도 반드시 실행할 cleanup 경계를 연다.
|
| 64줄F03-L64 | Pop-Location |
출고표 64번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 verify-core-v1-gate.ps1의 다음 검증 또는 설명 단계를 구성한다.
|
| 65줄F03-L65 | } |
출고표 65번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
STEP 05 / 13
원본 코드 조각
원본을 6개 의미 조각으로 나누어 그대로 확인합니다.
파일을 한꺼번에 외우지 않고 실행 의미가 이어지는 작은 조각으로 봅니다. 아래 코드는 hash로 고정한 native 정본 source에서 그대로 잘랐습니다.
param(
[Parameter(Mandatory=$true)][string]$ProjectRoot,
[Parameter(Mandatory=$true)][string]$EvidencePath,
[string]$ExpectedPath = ''
)
$ErrorActionPreference = 'Stop'
$reference = Split-Path -Parent $PSScriptRoot
$project = (Resolve-Path -LiteralPath $ProjectRoot).Path
if ([string]::IsNullOrWhiteSpace($ExpectedPath)) {
$ExpectedPath = Join-Path $reference 'learning_stages\w24\overlay\core-v1-expected.json'
}
$contract = Get-Content -LiteralPath $ExpectedPath -Raw | ConvertFrom-Json
$expected = @($contract.classes.psobject.Properties.Name | Sort-Object)
Push-Location $project
try {
& .\gradlew.bat clean coreV1Gate --no-daemon
if ($LASTEXITCODE -ne 0) { throw "coreV1Gate native exit=$LASTEXITCODE" }
$resultDirectory = Join-Path $project 'build\test-results\coreV1Gate'
$xmlFiles = @(Get-ChildItem -LiteralPath $resultDirectory -Filter 'TEST-*.xml' -File)
if ($xmlFiles.Count -eq 0) { throw 'coreV1Gate produced no XML test result' }
$rows = foreach ($file in $xmlFiles) {
[xml]$xml = Get-Content -LiteralPath $file.FullName -Raw
[pscustomobject]@{
class = [string]$xml.testsuite.name
tests = [int]$xml.testsuite.tests
failures = [int]$xml.testsuite.failures
errors = [int]$xml.testsuite.errors
skipped = [int]$xml.testsuite.skipped
}
}
$actual = @($rows.class | Sort-Object -Unique)
$missing = @($expected | Where-Object { $_ -notin $actual })
$unexpected = @($actual | Where-Object { $_ -notin $expected })
if ($missing.Count -gt 0 -or $unexpected.Count -gt 0) {
throw "class inventory mismatch; missing=$($missing -join ','); unexpected=$($unexpected -join ',')"
}
$tests = ($rows | Measure-Object tests -Sum).Sum
$failures = ($rows | Measure-Object failures -Sum).Sum
$errors = ($rows | Measure-Object errors -Sum).Sum
$skipped = ($rows | Measure-Object skipped -Sum).Sum
$wrongCounts = @($rows | Where-Object { $_.tests -ne [int]$contract.classes.psobject.Properties[$_.class].Value })
if ($actual.Count -ne 37 -or $tests -ne 66 -or $wrongCounts.Count -gt 0 -or $failures -ne 0 -or $errors -ne 0 -or $skipped -ne 0) {
throw "test summary is not Green: tests=$tests failures=$failures errors=$errors skipped=$skipped"
}
$summary = @(
'CORE_V1_GATE_GREEN',
"classes=$($actual.Count)",
"tests=$tests",
"failures=$failures",
"errors=$errors",
"skipped=$skipped"
)
$summary
$parent = Split-Path -Parent $EvidencePath
if (-not [string]::IsNullOrWhiteSpace($parent)) {
New-Item -ItemType Directory -Force -Path $parent | Out-Null
}
$summary | Set-Content -LiteralPath $EvidencePath -Encoding utf8
} finally {
Pop-Location
}
STEP 06 / 13
코드 한 줄씩 한국어로 번역
비어 있지 않은 61줄을 모두 한국어로 옮깁니다.
비어 있지 않은 원본 줄은 하나도 생략하지 않습니다.
| 줄 | 원본 | 한국어 번역 |
|---|---|---|
| 1 | param( | 실행 의미: PowerShell script가 받을 입력 계약을 연다. |
| 2 | [Parameter(Mandatory=$true)][string]$ProjectRoot, | 실행 의미: 이 인자가 빠지면 실행 시작 전에 binding을 거절한다. |
| 3 | [Parameter(Mandatory=$true)][string]$EvidencePath, | 실행 의미: 이 인자가 빠지면 실행 시작 전에 binding을 거절한다. |
| 4 | [string]$ExpectedPath = '' | 실행 의미: verify-core-v1-gate.ps1의 다음 검증 또는 설명 단계를 구성한다. |
| 5 | ) | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 7 | $ErrorActionPreference = 'Stop' | 실행 의미: PowerShell 오류를 계속 진행하지 않고 중단시키는 기본 정책을 둔다. |
| 8 | $reference = Split-Path -Parent $PSScriptRoot | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 9 | $project = (Resolve-Path -LiteralPath $ProjectRoot).Path | 실행 의미: 입력 경로를 실제 절대 경로로 확인한다. |
| 10 | if ([string]::IsNullOrWhiteSpace($ExpectedPath)) { | 실행 의미: 조건·반복·함수의 실행 block을 연다. |
| 11 | $ExpectedPath = Join-Path $reference 'learning_stages\w24\overlay\core-v1-expected.json' | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 12 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 13 | $contract = Get-Content -LiteralPath $ExpectedPath -Raw | ConvertFrom-Json | 실행 의미: JSON text를 필드로 접근 가능한 PowerShell object로 바꾼다. |
| 14 | $expected = @($contract.classes.psobject.Properties.Name | Sort-Object) | 실행 의미: class 이름과 기대 test 수를 exact inventory로 고정한다. |
| 15 | Push-Location $project | 실행 의미: verify-core-v1-gate.ps1의 다음 검증 또는 설명 단계를 구성한다. |
| 16 | try { | 실행 의미: 조건·반복·함수의 실행 block을 연다. |
| 17 | & .\gradlew.bat clean coreV1Gate --no-daemon | 실행 의미: learner project의 Gradle wrapper로 지정 task를 실행한다. |
| 18 | if ($LASTEXITCODE -ne 0) { throw "coreV1Gate native exit=$LASTEXITCODE" } | 실행 의미: native process 종료 코드를 검사해 실패를 놓치지 않는다. |
| 20 | $resultDirectory = Join-Path $project 'build\test-results\coreV1Gate' | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 21 | $xmlFiles = @(Get-ChildItem -LiteralPath $resultDirectory -Filter 'TEST-*.xml' -File) | 실행 의미: JUnit XML 결과 파일만 exact inventory 입력으로 모은다. |
| 22 | if ($xmlFiles.Count -eq 0) { throw 'coreV1Gate produced no XML test result' } | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 24 | $rows = foreach ($file in $xmlFiles) { | 실행 의미: 고정 목록의 각 항목에 같은 검사를 반복 적용한다. |
| 25 | [xml]$xml = Get-Content -LiteralPath $file.FullName -Raw | 실행 의미: verify-core-v1-gate.ps1의 다음 검증 또는 설명 단계를 구성한다. |
| 26 | [pscustomobject]@{ | 실행 의미: 조건·반복·함수의 실행 block을 연다. |
| 27 | class = [string]$xml.testsuite.name | 실행 의미: JUnit suite의 class 이름과 test/failure/error/skip 수를 읽는다. |
| 28 | tests = [int]$xml.testsuite.tests | 실행 의미: JUnit suite의 class 이름과 test/failure/error/skip 수를 읽는다. |
| 29 | failures = [int]$xml.testsuite.failures | 실행 의미: JUnit suite의 class 이름과 test/failure/error/skip 수를 읽는다. |
| 30 | errors = [int]$xml.testsuite.errors | 실행 의미: JUnit suite의 class 이름과 test/failure/error/skip 수를 읽는다. |
| 31 | skipped = [int]$xml.testsuite.skipped | 실행 의미: JUnit suite의 class 이름과 test/failure/error/skip 수를 읽는다. |
| 32 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 33 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 34 | $actual = @($rows.class | Sort-Object -Unique) | 실행 의미: Markdown 표 또는 PowerShell pipeline에서 값을 열이나 다음 명령으로 연결한다. |
| 35 | $missing = @($expected | Where-Object { $_ -notin $actual }) | 실행 의미: 조건을 만족하는 row만 필터링한다. |
| 36 | $unexpected = @($actual | Where-Object { $_ -notin $expected }) | 실행 의미: 조건을 만족하는 row만 필터링한다. |
| 37 | if ($missing.Count -gt 0 -or $unexpected.Count -gt 0) { | 실행 의미: 조건·반복·함수의 실행 block을 연다. |
| 38 | throw "class inventory mismatch; missing=$($missing -join ','); unexpected=$($unexpected -join ',')" | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 39 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 40 | $tests = ($rows | Measure-Object tests -Sum).Sum | 실행 의미: suite별 수치를 전체 합계로 계산한다. |
| 41 | $failures = ($rows | Measure-Object failures -Sum).Sum | 실행 의미: suite별 수치를 전체 합계로 계산한다. |
| 42 | $errors = ($rows | Measure-Object errors -Sum).Sum | 실행 의미: suite별 수치를 전체 합계로 계산한다. |
| 43 | $skipped = ($rows | Measure-Object skipped -Sum).Sum | 실행 의미: suite별 수치를 전체 합계로 계산한다. |
| 44 | $wrongCounts = @($rows | Where-Object { $_.tests -ne [int]$contract.classes.psobject.Properties[$_.class].Value }) | 실행 의미: class 이름과 기대 test 수를 exact inventory로 고정한다. |
| 45 | if ($actual.Count -ne 37 -or $tests -ne 66 -or $wrongCounts.Count -gt 0 -or $failures -ne 0 -or $errors -ne 0 -or $skipped -ne 0) { | 실행 의미: 조건·반복·함수의 실행 block을 연다. |
| 46 | throw "test summary is not Green: tests=$tests failures=$failures errors=$errors skipped=$skipped" | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 47 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 49 | $summary = @( | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 50 | 'CORE_V1_GATE_GREEN', | 실행 의미: 37 class·66 test·실패/오류/skip 0일 때만 exact local marker를 낸다. |
| 51 | "classes=$($actual.Count)", | 실행 의미: class 이름과 기대 test 수를 exact inventory로 고정한다. |
| 52 | "tests=$tests", | 실행 의미: verify-core-v1-gate.ps1의 다음 검증 또는 설명 단계를 구성한다. |
| 53 | "failures=$failures", | 실행 의미: verify-core-v1-gate.ps1의 다음 검증 또는 설명 단계를 구성한다. |
| 54 | "errors=$errors", | 실행 의미: verify-core-v1-gate.ps1의 다음 검증 또는 설명 단계를 구성한다. |
| 55 | "skipped=$skipped" | 실행 의미: verify-core-v1-gate.ps1의 다음 검증 또는 설명 단계를 구성한다. |
| 56 | ) | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 57 | $summary | 실행 의미: verify-core-v1-gate.ps1의 다음 검증 또는 설명 단계를 구성한다. |
| 58 | $parent = Split-Path -Parent $EvidencePath | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 59 | if (-not [string]::IsNullOrWhiteSpace($parent)) { | 실행 의미: 조건·반복·함수의 실행 block을 연다. |
| 60 | New-Item -ItemType Directory -Force -Path $parent | Out-Null | 실행 의미: Markdown 표 또는 PowerShell pipeline에서 값을 열이나 다음 명령으로 연결한다. |
| 61 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 62 | $summary | Set-Content -LiteralPath $EvidencePath -Encoding utf8 | 실행 의미: Markdown 표 또는 PowerShell pipeline에서 값을 열이나 다음 명령으로 연결한다. |
| 63 | } finally { | 실행 의미: 중간 실패가 있어도 반드시 실행할 cleanup 경계를 연다. |
| 64 | Pop-Location | 실행 의미: verify-core-v1-gate.ps1의 다음 검증 또는 설명 단계를 구성한다. |
| 65 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
STEP 07 / 13
기존 수준의 한 줄 읽기·문법 해부
쉬운 설명 다음에 문법과 실행 순서를 정밀하게 읽습니다.
한 줄로 읽기verify-core-v1-gate.ps1 — actual XML 37/66을 fail-closed 검증는 native Gradle exit, JUnit XML 존재, exact class set, class별 test 수와 failure/error/skip 0을 함께 확인한다.
문법 해부
- .ps1 문법에서 선언·조건·pipeline·block 경계를 먼저 나눈다.
- expected 값과 actual 결과를 같은 이름처럼 보여도 서로 다른 source로 읽는다.
- native exit·row count·hash·사람 판정을 서로 대체하지 않는다.
실행 순서
- 입력 경로·fixture·환경변수·expected 계약을 고정한다.
- source가 실행하는 native process·HTTP·SQL 또는 형식 검사를 따라간다.
- actual 값과 exact marker를 대조하고 실패면 성공 발행 전에 중단한다.
- finally cleanup과 비범위를 evidence에 남긴다.
W24 조각별 정밀 해설
F03-C01 · 원문 1–12줄
- 문법 해부
- .ps1 문법으로 1–12줄의 선언·조건·pipeline·block을 나눈다.
- 실제 값 추적
- CORE_V1_GATE_GREEN, classes=37, tests=66를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- expected와 actual이 일치하고 owner evidence가 같은 run/hash에 연결되는 경우다.
- 틀린 예·반례
- XML이 없으면 즉시 실패한다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- 파일 존재·문자열·hash·exit0 하나를 의미 Green 전체와 같다고 보지 않는다.
- 하지 않는 일
- XML이 없으면 즉시 실패한다; wildcard·0 tests 성공을 허용하지 않는다; 이 HTML은 runner를 실행하지 않았다
- 다음 연결
- 다음 조각 또는 F03 evidence 판정으로 상태를 넘긴다.
F03-C02 · 원문 13–24줄
- 문법 해부
- .ps1 문법으로 13–24줄의 선언·조건·pipeline·block을 나눈다.
- 실제 값 추적
- CORE_V1_GATE_GREEN, classes=37, tests=66를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- expected와 actual이 일치하고 owner evidence가 같은 run/hash에 연결되는 경우다.
- 틀린 예·반례
- XML이 없으면 즉시 실패한다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- 파일 존재·문자열·hash·exit0 하나를 의미 Green 전체와 같다고 보지 않는다.
- 하지 않는 일
- XML이 없으면 즉시 실패한다; wildcard·0 tests 성공을 허용하지 않는다; 이 HTML은 runner를 실행하지 않았다
- 다음 연결
- 다음 조각 또는 F03 evidence 판정으로 상태를 넘긴다.
F03-C03 · 원문 25–36줄
- 문법 해부
- .ps1 문법으로 25–36줄의 선언·조건·pipeline·block을 나눈다.
- 실제 값 추적
- CORE_V1_GATE_GREEN, classes=37, tests=66를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- expected와 actual이 일치하고 owner evidence가 같은 run/hash에 연결되는 경우다.
- 틀린 예·반례
- XML이 없으면 즉시 실패한다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- 파일 존재·문자열·hash·exit0 하나를 의미 Green 전체와 같다고 보지 않는다.
- 하지 않는 일
- XML이 없으면 즉시 실패한다; wildcard·0 tests 성공을 허용하지 않는다; 이 HTML은 runner를 실행하지 않았다
- 다음 연결
- 다음 조각 또는 F03 evidence 판정으로 상태를 넘긴다.
F03-C04 · 원문 37–48줄
- 문법 해부
- .ps1 문법으로 37–48줄의 선언·조건·pipeline·block을 나눈다.
- 실제 값 추적
- CORE_V1_GATE_GREEN, classes=37, tests=66를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- expected와 actual이 일치하고 owner evidence가 같은 run/hash에 연결되는 경우다.
- 틀린 예·반례
- XML이 없으면 즉시 실패한다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- 파일 존재·문자열·hash·exit0 하나를 의미 Green 전체와 같다고 보지 않는다.
- 하지 않는 일
- XML이 없으면 즉시 실패한다; wildcard·0 tests 성공을 허용하지 않는다; 이 HTML은 runner를 실행하지 않았다
- 다음 연결
- 다음 조각 또는 F03 evidence 판정으로 상태를 넘긴다.
F03-C05 · 원문 49–60줄
- 문법 해부
- .ps1 문법으로 49–60줄의 선언·조건·pipeline·block을 나눈다.
- 실제 값 추적
- CORE_V1_GATE_GREEN, classes=37, tests=66를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- expected와 actual이 일치하고 owner evidence가 같은 run/hash에 연결되는 경우다.
- 틀린 예·반례
- XML이 없으면 즉시 실패한다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- 파일 존재·문자열·hash·exit0 하나를 의미 Green 전체와 같다고 보지 않는다.
- 하지 않는 일
- XML이 없으면 즉시 실패한다; wildcard·0 tests 성공을 허용하지 않는다; 이 HTML은 runner를 실행하지 않았다
- 다음 연결
- 다음 조각 또는 F03 evidence 판정으로 상태를 넘긴다.
F03-C06 · 원문 61–65줄
- 문법 해부
- .ps1 문법으로 61–65줄의 선언·조건·pipeline·block을 나눈다.
- 실제 값 추적
- CORE_V1_GATE_GREEN, classes=37, tests=66를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- expected와 actual이 일치하고 owner evidence가 같은 run/hash에 연결되는 경우다.
- 틀린 예·반례
- XML이 없으면 즉시 실패한다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- 파일 존재·문자열·hash·exit0 하나를 의미 Green 전체와 같다고 보지 않는다.
- 하지 않는 일
- XML이 없으면 즉시 실패한다; wildcard·0 tests 성공을 허용하지 않는다; 이 HTML은 runner를 실행하지 않았다
- 다음 연결
- 다음 조각 또는 F03 evidence 판정으로 상태를 넘긴다.
실행 순서 — 66을 fail-closed 검증
-
classes=37가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 native Gradle exit, JUnit XML 존재, exact class set, class별 test 수와 failure/error/skip 0을 함께 확인한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘wildcard·0 tests 성공을 허용하지 않는다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 classes=37와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 08 / 13
실제 값 따라가기
같은 입력값이 어느 줄을 지나 어떤 결과가 되는지 추적합니다.
| 순서 | 들어온 값 | 코드가 하는 일 | 나온 값·상태 | 경계 |
|---|---|---|---|---|
| 입력 | CORE_V1_GATE_GREEN | source 계약에 대입 | F03 실행/설명 시작 상태 | XML이 없으면 즉시 실패한다 |
| 검증 | classes=37 | expected와 actual 또는 형식 대조 | 통과 또는 첫 mismatch | wildcard·0 tests 성공을 허용하지 않는다 |
| 증거 | failures/errors/skipped=0 | marker·hash·row를 같은 run에 연결 | 범위가 적힌 evidence 후보 | 이 HTML은 runner를 실행하지 않았다 |
실제 값 — 66을 fail-closed 검증
-
tests=66가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 native Gradle exit, JUnit XML 존재, exact class set, class별 test 수와 failure/error/skip 0을 함께 확인한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘이 HTML은 runner를 실행하지 않았다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 tests=66와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 09 / 13
Gradle·PowerShell·HTTP·PostgreSQL 내부에서 벌어지는 일
Gradle·JUnit XML·PowerShell·HTTP·PostgreSQL·Docker에서 실제로 일어나는 일과 증명 범위를 구분합니다.
verify-core-v1-gate.ps1 bytes와 expected 값을 읽는다.
파일 존재만으로 runtime 성공은 아니다.native exit·HTTP status·JUnit XML·DB row·hash 중 이 파일이 소유한 값을 만든다.
XML이 없으면 즉시 실패한다관련 evidence와 사람 의미 검토를 release 후보에 연결한다.
이 HTML은 runner를 실행하지 않았다첫 실패 경계 — 66을 fail-closed 검증
-
failures/errors/skipped=0가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 native Gradle exit, JUnit XML 존재, exact class set, class별 test 수와 failure/error/skip 0을 함께 확인한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘XML이 없으면 즉시 실패한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 failures/errors/skipped=0와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 10 / 13
흔한 착각과 틀린 예
그럴듯하지만 틀린 해석을 반례로 고칩니다.
❌ CORE_V1_GATE_GREEN 문자열이 source에 있으니 실제 실행도 Green이다.
왜 틀리나 source literal과 runtime 관찰값은 다른 증거다.
바르게 읽기 native exit·actual XML/HTTP/DB evidence를 별도로 확인한다.
반례 script가 실행 전 경로 오류로 멈춰도 literal은 그대로 남는다.
❌ 파일 SHA-256이 있으면 내용의 의미와 사실성도 검증됐다.
왜 틀리나 hash는 동일 bytes만 말한다.
바르게 읽기 schema·수치·질문·근거는 별도 자동 또는 사람 판정을 거친다.
반례 빈 review 질문을 가진 CSV도 안정된 hash를 가진다.
❌ LOCAL_ARTIFACT_VALIDATED는 release Green과 같다.
왜 틀리나 generic validator는 파일 shape만 확인한다.
바르게 읽기 HUMAN_SEMANTIC_REVIEW_REQUIRED를 유지한다.
반례 잘못된 track 점수표도 byte 수 조건은 통과할 수 있다.
❌ 이 파일이 W24 전체 lifecycle을 모두 소유한다.
왜 틀리나 각 source는 Gate·demo·cleanup·사람 review 중 일부만 담당한다.
바르게 읽기 owner와 non-responsibility를 release manifest에서 분리한다.
반례 D4 source audit에는 runtime_claim=false가 명시된다.
❌ 이전 주 Green이나 오래된 log를 현재 commit 결과로 재사용한다.
왜 틀리나 source·commit·actual result가 같은 실행에 묶이지 않는다.
바르게 읽기 release 후보에서 새 evidence와 hash를 만든다.
반례 expected JSON이 바뀌면 예전 XML은 exact inventory를 증명하지 못한다.
STEP 11 / 13
이 코드가 보장하지 않는 것
이 코드가 책임지지 않는 일을 분리합니다.
XML이 없으면 즉시 실패한다
이 책임을 맡는 곳: runtime Gatewildcard·0 tests 성공을 허용하지 않는다
이 책임을 맡는 곳: external/human review이 HTML은 runner를 실행하지 않았다
이 책임을 맡는 곳: release manifestXML이 없으면 즉시 실패한다
이 책임을 맡는 곳: 운영 환경증명하지 않는 범위 — 66을 fail-closed 검증
-
CORE_V1_GATE_GREEN가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 native Gradle exit, JUnit XML 존재, exact class set, class별 test 수와 failure/error/skip 0을 함께 확인한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘wildcard·0 tests 성공을 허용하지 않는다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 CORE_V1_GATE_GREEN와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 12 / 13
직접 다시 써보기
뜻 → 조각 → 전체 코드 순서로 다시 씁니다.
1단계 · 뜻부터 복원
- native Gradle exit, JUnit XML 존재, exact class set, class별 test 수와 failure/error/skip 0을 함께 확인한다.
- 핵심 값은 CORE_V1_GATE_GREEN, classes=37, tests=66, failures/errors/skipped=0다.
2단계 · 코드 조각 재조립
- 1. PowerShell script가 받을 입력 계약을 연다
- 2. 이 인자가 빠지면 실행 시작 전에 binding을 거절한다
- 3. 이 인자가 빠지면 실행 시작 전에 binding을 거절한다
- 4. verify-core-v1-gate.ps1의 다음 검증 또는 설명 단계를 구성한다
- 5. 앞에서 연 block 또는 호출 범위를 닫는다
- 7. PowerShell 오류를 계속 진행하지 않고 중단시키는 기본 정책을 둔다
- 8. 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다
- 9. 입력 경로를 실제 절대 경로로 확인한다
3단계 · 파일 전체 다시 쓰기
scripts/verify-core-v1-gate.ps1을 새 파일에 다시 쓰고 expected·actual·실패·cleanup·비범위를 주석으로 표시한다.
자가 점검
- 비어 있지 않은 모든 source 줄을 한 번씩 읽었나?
- source shape와 runtime Green을 분리했나?
- 사람 검토·외부 상태를 자동 성공으로 꾸미지 않았나?
- 첫 실패와 cleanup 책임을 설명할 수 있나?
STEP 13 / 13
전체 원본 source
감사로 고정한 전체 source를 가감 없이 확인합니다.
원문 정본 전체 source 확인하기
param(
[Parameter(Mandatory=$true)][string]$ProjectRoot,
[Parameter(Mandatory=$true)][string]$EvidencePath,
[string]$ExpectedPath = ''
)
$ErrorActionPreference = 'Stop'
$reference = Split-Path -Parent $PSScriptRoot
$project = (Resolve-Path -LiteralPath $ProjectRoot).Path
if ([string]::IsNullOrWhiteSpace($ExpectedPath)) {
$ExpectedPath = Join-Path $reference 'learning_stages\w24\overlay\core-v1-expected.json'
}
$contract = Get-Content -LiteralPath $ExpectedPath -Raw | ConvertFrom-Json
$expected = @($contract.classes.psobject.Properties.Name | Sort-Object)
Push-Location $project
try {
& .\gradlew.bat clean coreV1Gate --no-daemon
if ($LASTEXITCODE -ne 0) { throw "coreV1Gate native exit=$LASTEXITCODE" }
$resultDirectory = Join-Path $project 'build\test-results\coreV1Gate'
$xmlFiles = @(Get-ChildItem -LiteralPath $resultDirectory -Filter 'TEST-*.xml' -File)
if ($xmlFiles.Count -eq 0) { throw 'coreV1Gate produced no XML test result' }
$rows = foreach ($file in $xmlFiles) {
[xml]$xml = Get-Content -LiteralPath $file.FullName -Raw
[pscustomobject]@{
class = [string]$xml.testsuite.name
tests = [int]$xml.testsuite.tests
failures = [int]$xml.testsuite.failures
errors = [int]$xml.testsuite.errors
skipped = [int]$xml.testsuite.skipped
}
}
$actual = @($rows.class | Sort-Object -Unique)
$missing = @($expected | Where-Object { $_ -notin $actual })
$unexpected = @($actual | Where-Object { $_ -notin $expected })
if ($missing.Count -gt 0 -or $unexpected.Count -gt 0) {
throw "class inventory mismatch; missing=$($missing -join ','); unexpected=$($unexpected -join ',')"
}
$tests = ($rows | Measure-Object tests -Sum).Sum
$failures = ($rows | Measure-Object failures -Sum).Sum
$errors = ($rows | Measure-Object errors -Sum).Sum
$skipped = ($rows | Measure-Object skipped -Sum).Sum
$wrongCounts = @($rows | Where-Object { $_.tests -ne [int]$contract.classes.psobject.Properties[$_.class].Value })
if ($actual.Count -ne 37 -or $tests -ne 66 -or $wrongCounts.Count -gt 0 -or $failures -ne 0 -or $errors -ne 0 -or $skipped -ne 0) {
throw "test summary is not Green: tests=$tests failures=$failures errors=$errors skipped=$skipped"
}
$summary = @(
'CORE_V1_GATE_GREEN',
"classes=$($actual.Count)",
"tests=$tests",
"failures=$failures",
"errors=$errors",
"skipped=$skipped"
)
$summary
$parent = Split-Path -Parent $EvidencePath
if (-not [string]::IsNullOrWhiteSpace($parent)) {
New-Item -ItemType Directory -Force -Path $parent | Out-Null
}
$summary | Set-Content -LiteralPath $EvidencePath -Encoding utf8
} finally {
Pop-Location
}
04W24 D1 test inventory — actual XML을 evidence에 원자 저장
illustrative/powershell/W24-D1-primary-evidence-closure.ps1
학습용 예시 · PDF inline PowerShell · 정본 답안 아님 · 비실행 · 학습용 예시 · 정본 답안 아님 · W24-F0484줄 연결84줄 번역8 chunks
W24 D1 test inventory — actual XML을 evidence에 원자 저장
illustrative/powershell/W24-D1-primary-evidence-closure.ps1
학습용 예시 · PDF inline PowerShell · 정본 답안 아님 · 비실행 · 학습용 예시 · 정본 답안 아님 · W24-F04STEP 01 / 13
오늘 이 코드에서 해결할 문제
무엇을 이해해야 하는지 질문부터 잡습니다.
PDF p789의 당일 evidence closure를 가독성 있게 정리해 class별 XML hash와 aggregate를 test-inventory.md에 묶는다.
- actual_xml=37은 어느 source와 실제 결과에서 확인해야 할까?
- 첫 실패를 만드는 조건과 fail-closed 지점은 어디일까?
- 왜 ‘PDF-only 학습 예시이며 packaged 정본이 아니다’를 별도 경계로 남겨야 할까?
actual_xml=37tests=66atomic tmp moveexpected/gate SHA-256왜 필요한가 — W24 D1 test inventory — actual XML을 evidence에 원자 저장
-
actual_xml=37가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 PDF p789의 당일 evidence closure를 가독성 있게 정리해 class별 XML hash와 aggregate를 test-inventory.md에 묶는다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘PDF-only 학습 예시이며 packaged 정본이 아니다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 actual_xml=37와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 02 / 13
아주 짧게: 이 코드는 왜 필요할까?
웹소설 대신 이 코드가 필요한 이유만 두 문단으로 쉽게 봅니다.
새 기능을 멈춘 팀이 코드·test·문서·demo를 같은 release 후보에 묶어 하나씩 검수한다.
검수 도장이 붙은 공통 거래 코어 출고 상자
이 파일은 PDF p789의 당일 evidence closure를 가독성 있게 정리해 class별 XML hash와 aggregate를 test-inventory.md에 묶는다. 눈으로 읽을 때는 각 줄을 검수표 한 칸처럼 보고, 입력과 다음 상태를 놓치지 않는다.
마지막 도장은 source shape와 실제 runtime·사람 검토를 구분한 뒤에만 찍는다. 특히 PDF-only 학습 예시이며 packaged 정본이 아니다
딱 여기까지만 비유는 실행 순서를 돕지만 실제 Gradle·Docker·DB·사람 review를 대신하지 않는다.
STEP 03 / 13
초등학생도 이해하는 설명
생활 비유와 실제 코드의 경계를 함께 확인합니다.
값 1: actual_xml=37
이 파일에서 계속 확인할 고정 단서가 actual_xml=37다.
- 코드 연결
F04 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- PDF-only 학습 예시이며 packaged 정본이 아니다
값 2: tests=66
이 파일에서 계속 확인할 고정 단서가 tests=66다.
- 코드 연결
F04 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- 고정 숫자만 적은 문서는 통과하지 않는다
값 3: atomic tmp move
이 파일에서 계속 확인할 고정 단서가 atomic tmp move다.
- 코드 연결
F04 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- 실제 실행 결과를 주장하지 않는다
값 4: expected/gate SHA-256
이 파일에서 계속 확인할 고정 단서가 expected/gate SHA-256다.
- 코드 연결
F04 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- PDF-only 학습 예시이며 packaged 정본이 아니다
STEP 04 / 13
비유 ↔ 코드 전체 연결표
감사 규칙상 연결 대상인 원본 84줄을 빠짐없이 연결합니다.
| 줄 | 정확한 원본 줄 | STARRY 비유 | 실제 뜻·입력·결과·한계 |
|---|---|---|---|
| 1줄F04-L01 | # W24 PDF p789에서 제공한 당일 Gate를 읽기 좋게 정리한 학습용 예시다. |
출고표 1번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다.
|
| 2줄F04-L02 | # packaged reference source가 아니며, |
출고표 2번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다.
|
| 3줄F04-L03 | $PRIMARY_PRODUCER = |
출고표 3번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 4줄F04-L04 | $Artifact = |
출고표 4번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 5줄F04-L05 | $Verifier = |
출고표 5번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 6줄F04-L06 | $GateText = |
출고표 6번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 8줄F04-L08 | & powershell. |
출고표 8번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W24-D1-primary-evidence-closure.ps1의 다음 검증 또는 설명 단계를 구성한다.
|
| 9줄F04-L09 | -ProjectRoot $LearnerRoot -EvidencePath $GateText |
출고표 9번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W24-D1-primary-evidence-closure.ps1의 다음 검증 또는 설명 단계를 구성한다.
|
| 10줄F04-L10 | if ( |
출고표 10번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 native process 종료 코드를 검사해 실패를 놓치지 않는다.
|
| 11줄F04-L11 | throw "W24D1 core verifier native exit= |
출고표 11번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 native process 종료 코드를 검사해 실패를 놓치지 않는다.
|
| 12줄F04-L12 | } |
출고표 12번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 14줄F04-L14 | $ExpectedPath = |
출고표 14번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 15줄F04-L15 | $Expected = |
출고표 15번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 JSON text를 필드로 접근 가능한 PowerShell object로 바꾼다.
|
| 16줄F04-L16 | $ResultDir = |
출고표 16번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 17줄F04-L17 | $Rows = |
출고표 17번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 JUnit XML 결과 파일만 exact inventory 입력으로 모은다.
|
| 18줄F04-L18 | [ |
출고표 18번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W24-D1-primary-evidence-closure.ps1의 다음 검증 또는 설명 단계를 구성한다.
|
| 19줄F04-L19 | [ |
출고표 19번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 조건·반복·함수의 실행 block을 연다.
|
| 20줄F04-L20 | class = |
출고표 20번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 JUnit suite의 class 이름과 test/failure/error/skip 수를 읽는다.
|
| 21줄F04-L21 | tests = |
출고표 21번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 JUnit suite의 class 이름과 test/failure/error/skip 수를 읽는다.
|
| 22줄F04-L22 | failures = |
출고표 22번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 JUnit suite의 class 이름과 test/failure/error/skip 수를 읽는다.
|
| 23줄F04-L23 | errors = |
출고표 23번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 JUnit suite의 class 이름과 test/failure/error/skip 수를 읽는다.
|
| 24줄F04-L24 | skipped = |
출고표 24번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 JUnit suite의 class 이름과 test/failure/error/skip 수를 읽는다.
|
| 25줄F04-L25 | xml_sha256 = |
출고표 25번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 현재 bytes를 64자리 digest로 evidence에 결박한다.
|
| 26줄F04-L26 | } |
출고표 26번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 27줄F04-L27 | }) |
출고표 27번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 29줄F04-L29 | $ExpectedNames = |
출고표 29번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 class 이름과 기대 test 수를 exact inventory로 고정한다.
|
| 30줄F04-L30 | $ActualNames = |
출고표 30번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 Markdown 표 또는 PowerShell pipeline에서 값을 열이나 다음 명령으로 연결한다.
|
| 31줄F04-L31 | if ( |
출고표 31번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 expected와 actual 집합에 누락·예상 밖 항목이 있는지 비교한다.
|
| 32줄F04-L32 | throw 'W24D1 actual XML class set differs from canonical expectation' |
출고표 32번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 33줄F04-L33 | } |
출고표 33번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 34줄F04-L34 | foreach ( |
출고표 34번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 고정 목록의 각 항목에 같은 검사를 반복 적용한다.
|
| 35줄F04-L35 | $ExpectedTests = |
출고표 35번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 class 이름과 기대 test 수를 exact inventory로 고정한다.
|
| 36줄F04-L36 | if ( |
출고표 36번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 조건·반복·함수의 실행 block을 연다.
|
| 37줄F04-L37 | throw "W24D1 class/ |
출고표 37번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 38줄F04-L38 | } |
출고표 38번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 39줄F04-L39 | } |
출고표 39번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 41줄F04-L41 | $Tests = |
출고표 41번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 suite별 수치를 전체 합계로 계산한다.
|
| 42줄F04-L42 | $Failures = |
출고표 42번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 suite별 수치를 전체 합계로 계산한다.
|
| 43줄F04-L43 | $Errors = |
출고표 43번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 suite별 수치를 전체 합계로 계산한다.
|
| 44줄F04-L44 | $Skipped = |
출고표 44번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 suite별 수치를 전체 합계로 계산한다.
|
| 45줄F04-L45 | if ( |
출고표 45번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 조건·반복·함수의 실행 block을 연다.
|
| 46줄F04-L46 | throw "W24D1 actual aggregate mismatch classes= |
출고표 46번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 class 이름과 기대 test 수를 exact inventory로 고정한다.
|
| 47줄F04-L47 | } |
출고표 47번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 49줄F04-L49 | $Gate = |
출고표 49번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 50줄F04-L50 | foreach ( |
출고표 50번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 class 이름과 기대 test 수를 exact inventory로 고정한다.
|
| 51줄F04-L51 | if ( |
출고표 51번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 조건·반복·함수의 실행 block을 연다.
|
| 52줄F04-L52 | throw "W24D1 gate marker missing: |
출고표 52번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 53줄F04-L53 | } |
출고표 53번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 54줄F04-L54 | } |
출고표 54번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 56줄F04-L56 | $ExpectedHash = |
출고표 56번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 현재 bytes를 64자리 digest로 evidence에 결박한다.
|
| 57줄F04-L57 | $GateHash = |
출고표 57번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 현재 bytes를 64자리 digest로 evidence에 결박한다.
|
| 58줄F04-L58 | $Lines = |
출고표 58번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 59줄F04-L59 | '# W24 test inventory', |
출고표 59번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다.
|
| 60줄F04-L60 | 'status: |
출고표 60번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W24-D1-primary-evidence-closure.ps1의 다음 검증 또는 설명 단계를 구성한다.
|
| 61줄F04-L61 | 'source: |
출고표 61번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W24-D1-primary-evidence-closure.ps1의 다음 검증 또는 설명 단계를 구성한다.
|
| 62줄F04-L62 | "classes: |
출고표 62번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 class 이름과 기대 test 수를 exact inventory로 고정한다.
|
| 63줄F04-L63 | "tests: |
출고표 63번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W24-D1-primary-evidence-closure.ps1의 다음 검증 또는 설명 단계를 구성한다.
|
| 64줄F04-L64 | "failures: |
출고표 64번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W24-D1-primary-evidence-closure.ps1의 다음 검증 또는 설명 단계를 구성한다.
|
| 65줄F04-L65 | "errors: |
출고표 65번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W24-D1-primary-evidence-closure.ps1의 다음 검증 또는 설명 단계를 구성한다.
|
| 66줄F04-L66 | "skipped: |
출고표 66번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W24-D1-primary-evidence-closure.ps1의 다음 검증 또는 설명 단계를 구성한다.
|
| 67줄F04-L67 | "expected_sha256: |
출고표 67번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 현재 bytes를 64자리 digest로 evidence에 결박한다.
|
| 68줄F04-L68 | "gate_sha256: |
출고표 68번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 현재 bytes를 64자리 digest로 evidence에 결박한다.
|
| 69줄F04-L69 | '', |
출고표 69번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W24-D1-primary-evidence-closure.ps1의 다음 검증 또는 설명 단계를 구성한다.
|
| 70줄F04-L70 | '| class | tests | failures | errors | skipped | xml_sha256 |', |
출고표 70번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 현재 bytes를 64자리 digest로 evidence에 결박한다.
|
| 71줄F04-L71 | '|---|---: |
출고표 71번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 Markdown 표 또는 PowerShell pipeline에서 값을 열이나 다음 명령으로 연결한다.
|
| 72줄F04-L72 | ) |
출고표 72번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 73줄F04-L73 | $Lines + |
출고표 73번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 고정 목록의 각 항목에 같은 검사를 반복 적용한다.
|
| 74줄F04-L74 | "| $( |
출고표 74번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 현재 bytes를 64자리 digest로 evidence에 결박한다.
|
| 75줄F04-L75 | }) |
출고표 75번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 77줄F04-L77 | $Tmp = |
출고표 77번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 78줄F04-L78 | New-Item -ItemType Directory -Force ( |
출고표 78번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 Markdown 표 또는 PowerShell pipeline에서 값을 열이나 다음 명령으로 연결한다.
|
| 79줄F04-L79 | $Lines | Set-Content -Encoding utf8 $Tmp |
출고표 79번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 Markdown 표 또는 PowerShell pipeline에서 값을 열이나 다음 명령으로 연결한다.
|
| 80줄F04-L80 | $Saved = |
출고표 80번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 81줄F04-L81 | foreach ( |
출고표 81번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 class 이름과 기대 test 수를 exact inventory로 고정한다.
|
| 82줄F04-L82 | if ( |
출고표 82번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 조건·반복·함수의 실행 block을 연다.
|
| 83줄F04-L83 | throw "W24D1 inventory marker missing: |
출고표 83번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 84줄F04-L84 | } |
출고표 84번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 85줄F04-L85 | } |
출고표 85번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 86줄F04-L86 | Move-Item -Force -LiteralPath $Tmp -Destination $Artifact |
출고표 86번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W24-D1-primary-evidence-closure.ps1의 다음 검증 또는 설명 단계를 구성한다.
|
| 87줄F04-L87 | if ( |
출고표 87번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 필수 파일이나 경로가 실제로 있는지 확인한다.
|
| 88줄F04-L88 | throw 'W24D1 atomic inventory move failed' |
출고표 88번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 89줄F04-L89 | } |
출고표 89번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 90줄F04-L90 | $Hash = |
출고표 90번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 현재 bytes를 64자리 digest로 evidence에 결박한다.
|
| 91줄F04-L91 | "W24D1_PRIMARY_EVIDENCE_GREEN classes= |
출고표 91번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 class 이름과 기대 test 수를 exact inventory로 고정한다.
|
STEP 05 / 13
원본 코드 조각
원본을 8개 의미 조각으로 나누어 그대로 확인합니다.
파일을 한꺼번에 외우지 않고 실행 의미가 이어지는 작은 조각으로 봅니다. 아래 코드는 prompt·fixture·가정을 밝힌 학습용 예시 source이며, 제공 정본 답안이 아닙니다.
# W24 PDF p789에서 제공한 당일 Gate를 읽기 좋게 정리한 학습용 예시다.
# packaged reference source가 아니며, 실제 Gradle/JUnit 실행 결과도 아니다.
$PRIMARY_PRODUCER = 1
$Artifact = Join-Path $LearnerRoot 'evidence\w24\test-inventory.md'
$Verifier = Join-Path $ReferenceRoot 'scripts\verify-core-v1-gate.ps1'
$GateText = Join-Path $LearnerRoot 'evidence\w24\core-v1-gate.txt'
& powershell.exe -NoProfile -ExecutionPolicy Bypass -File $Verifier `
-ProjectRoot $LearnerRoot -EvidencePath $GateText
if ($LASTEXITCODE -ne 0) {
throw "W24D1 core verifier native exit=$LASTEXITCODE"
}
$ExpectedPath = Join-Path $ReferenceRoot 'learning_stages\w24\overlay\core-v1-expected.json'
$Expected = Get-Content -Raw -LiteralPath $ExpectedPath | ConvertFrom-Json
$ResultDir = Join-Path $LearnerRoot 'build\test-results\coreV1Gate'
$Rows = @(Get-ChildItem -LiteralPath $ResultDir -Filter 'TEST-*.xml' -File | ForEach-Object {
[xml]$Xml = Get-Content -Raw -LiteralPath $_.FullName
[pscustomobject]@{
class = [string]$Xml.testsuite.name
tests = [int]$Xml.testsuite.tests
failures = [int]$Xml.testsuite.failures
errors = [int]$Xml.testsuite.errors
skipped = [int]$Xml.testsuite.skipped
xml_sha256 = (Get-FileHash -LiteralPath $_.FullName -Algorithm SHA256).Hash.ToLowerInvariant()
}
})
$ExpectedNames = @($Expected.classes.psobject.Properties.Name | Sort-Object)
$ActualNames = @($Rows.class | Sort-Object -Unique)
if (Compare-Object $ExpectedNames $ActualNames) {
throw 'W24D1 actual XML class set differs from canonical expectation'
}
foreach ($Row in $Rows) {
$ExpectedTests = [int]$Expected.classes.psobject.Properties[$Row.class].Value
if ($Row.tests -ne $ExpectedTests -or $Row.failures -ne 0 -or $Row.errors -ne 0 -or $Row.skipped -ne 0) {
throw "W24D1 class/count/status mismatch: $($Row.class)"
}
}
$Tests = ($Rows | Measure-Object tests -Sum).Sum
$Failures = ($Rows | Measure-Object failures -Sum).Sum
$Errors = ($Rows | Measure-Object errors -Sum).Sum
$Skipped = ($Rows | Measure-Object skipped -Sum).Sum
if ($Rows.Count -ne 37 -or $Tests -ne 66 -or $Failures -ne 0 -or $Errors -ne 0 -or $Skipped -ne 0) {
throw "W24D1 actual aggregate mismatch classes=$($Rows.Count) tests=$Tests"
}
$Gate = Get-Content -Raw -LiteralPath $GateText
foreach ($Token in @('CORE_V1_GATE_GREEN', 'classes=37', 'tests=66', 'failures=0', 'errors=0', 'skipped=0')) {
if ($Gate -cnotmatch [regex]::Escape($Token)) {
throw "W24D1 gate marker missing: $Token"
}
}
$ExpectedHash = (Get-FileHash -LiteralPath $ExpectedPath -Algorithm SHA256).Hash.ToLowerInvariant()
$GateHash = (Get-FileHash -LiteralPath $GateText -Algorithm SHA256).Hash.ToLowerInvariant()
$Lines = @(
'# W24 test inventory',
'status: GREEN',
'source: actual coreV1Gate XML',
"classes: $($Rows.Count)",
"tests: $Tests",
"failures: $Failures",
"errors: $Errors",
"skipped: $Skipped",
"expected_sha256: $ExpectedHash",
"gate_sha256: $GateHash",
'',
'| class | tests | failures | errors | skipped | xml_sha256 |',
'|---|---:|---:|---:|---:|---|'
)
$Lines += @($Rows | Sort-Object class | ForEach-Object {
"| $($_.class) | $($_.tests) | $($_.failures) | $($_.errors) | $($_.skipped) | $($_.xml_sha256) |"
})
$Tmp = "$Artifact.tmp"
New-Item -ItemType Directory -Force (Split-Path -Parent $Artifact) | Out-Null
$Lines | Set-Content -Encoding utf8 $Tmp
$Saved = Get-Content -Raw -LiteralPath $Tmp
foreach ($Token in @('source: actual coreV1Gate XML', 'classes: 37', 'tests: 66', 'failures: 0', 'errors: 0', 'skipped: 0', "expected_sha256: $ExpectedHash", "gate_sha256: $GateHash")) {
if ($Saved -cnotmatch [regex]::Escape($Token)) {
throw "W24D1 inventory marker missing: $Token"
}
}
Move-Item -Force -LiteralPath $Tmp -Destination $Artifact
if (!(Test-Path -LiteralPath $Artifact -PathType Leaf)) {
throw 'W24D1 atomic inventory move failed'
}
$Hash = (Get-FileHash -LiteralPath $Artifact -Algorithm SHA256).Hash.ToLowerInvariant()
"W24D1_PRIMARY_EVIDENCE_GREEN classes=37 tests=66 failures=0 errors=0 skipped=0 actual_xml=37 sha256=$Hash"
STEP 06 / 13
코드 한 줄씩 한국어로 번역
비어 있지 않은 84줄을 모두 한국어로 옮깁니다.
비어 있지 않은 원본 줄은 하나도 생략하지 않습니다.
| 줄 | 원본 | 한국어 번역 |
|---|---|---|
| 1 | # W24 PDF p789에서 제공한 당일 Gate를 읽기 좋게 정리한 학습용 예시다. | 문서 의미: 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다. |
| 2 | # packaged reference source가 아니며, 실제 Gradle/JUnit 실행 결과도 아니다. | 문서 의미: 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다. |
| 3 | $PRIMARY_PRODUCER = 1 | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 4 | $Artifact = Join-Path $LearnerRoot 'evidence\w24\test-inventory.md' | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 5 | $Verifier = Join-Path $ReferenceRoot 'scripts\verify-core-v1-gate.ps1' | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 6 | $GateText = Join-Path $LearnerRoot 'evidence\w24\core-v1-gate.txt' | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 8 | & powershell.exe -NoProfile -ExecutionPolicy Bypass -File $Verifier ` | 실행 의미: W24-D1-primary-evidence-closure.ps1의 다음 검증 또는 설명 단계를 구성한다. |
| 9 | -ProjectRoot $LearnerRoot -EvidencePath $GateText | 실행 의미: W24-D1-primary-evidence-closure.ps1의 다음 검증 또는 설명 단계를 구성한다. |
| 10 | if ($LASTEXITCODE -ne 0) { | 실행 의미: native process 종료 코드를 검사해 실패를 놓치지 않는다. |
| 11 | throw "W24D1 core verifier native exit=$LASTEXITCODE" | 실행 의미: native process 종료 코드를 검사해 실패를 놓치지 않는다. |
| 12 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 14 | $ExpectedPath = Join-Path $ReferenceRoot 'learning_stages\w24\overlay\core-v1-expected.json' | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 15 | $Expected = Get-Content -Raw -LiteralPath $ExpectedPath | ConvertFrom-Json | 실행 의미: JSON text를 필드로 접근 가능한 PowerShell object로 바꾼다. |
| 16 | $ResultDir = Join-Path $LearnerRoot 'build\test-results\coreV1Gate' | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 17 | $Rows = @(Get-ChildItem -LiteralPath $ResultDir -Filter 'TEST-*.xml' -File | ForEach-Object { | 실행 의미: JUnit XML 결과 파일만 exact inventory 입력으로 모은다. |
| 18 | [xml]$Xml = Get-Content -Raw -LiteralPath $_.FullName | 실행 의미: W24-D1-primary-evidence-closure.ps1의 다음 검증 또는 설명 단계를 구성한다. |
| 19 | [pscustomobject]@{ | 실행 의미: 조건·반복·함수의 실행 block을 연다. |
| 20 | class = [string]$Xml.testsuite.name | 실행 의미: JUnit suite의 class 이름과 test/failure/error/skip 수를 읽는다. |
| 21 | tests = [int]$Xml.testsuite.tests | 실행 의미: JUnit suite의 class 이름과 test/failure/error/skip 수를 읽는다. |
| 22 | failures = [int]$Xml.testsuite.failures | 실행 의미: JUnit suite의 class 이름과 test/failure/error/skip 수를 읽는다. |
| 23 | errors = [int]$Xml.testsuite.errors | 실행 의미: JUnit suite의 class 이름과 test/failure/error/skip 수를 읽는다. |
| 24 | skipped = [int]$Xml.testsuite.skipped | 실행 의미: JUnit suite의 class 이름과 test/failure/error/skip 수를 읽는다. |
| 25 | xml_sha256 = (Get-FileHash -LiteralPath $_.FullName -Algorithm SHA256).Hash.ToLowerInvariant() | 실행 의미: 현재 bytes를 64자리 digest로 evidence에 결박한다. |
| 26 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 27 | }) | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 29 | $ExpectedNames = @($Expected.classes.psobject.Properties.Name | Sort-Object) | 실행 의미: class 이름과 기대 test 수를 exact inventory로 고정한다. |
| 30 | $ActualNames = @($Rows.class | Sort-Object -Unique) | 실행 의미: Markdown 표 또는 PowerShell pipeline에서 값을 열이나 다음 명령으로 연결한다. |
| 31 | if (Compare-Object $ExpectedNames $ActualNames) { | 실행 의미: expected와 actual 집합에 누락·예상 밖 항목이 있는지 비교한다. |
| 32 | throw 'W24D1 actual XML class set differs from canonical expectation' | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 33 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 34 | foreach ($Row in $Rows) { | 실행 의미: 고정 목록의 각 항목에 같은 검사를 반복 적용한다. |
| 35 | $ExpectedTests = [int]$Expected.classes.psobject.Properties[$Row.class].Value | 실행 의미: class 이름과 기대 test 수를 exact inventory로 고정한다. |
| 36 | if ($Row.tests -ne $ExpectedTests -or $Row.failures -ne 0 -or $Row.errors -ne 0 -or $Row.skipped -ne 0) { | 실행 의미: 조건·반복·함수의 실행 block을 연다. |
| 37 | throw "W24D1 class/count/status mismatch: $($Row.class)" | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 38 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 39 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 41 | $Tests = ($Rows | Measure-Object tests -Sum).Sum | 실행 의미: suite별 수치를 전체 합계로 계산한다. |
| 42 | $Failures = ($Rows | Measure-Object failures -Sum).Sum | 실행 의미: suite별 수치를 전체 합계로 계산한다. |
| 43 | $Errors = ($Rows | Measure-Object errors -Sum).Sum | 실행 의미: suite별 수치를 전체 합계로 계산한다. |
| 44 | $Skipped = ($Rows | Measure-Object skipped -Sum).Sum | 실행 의미: suite별 수치를 전체 합계로 계산한다. |
| 45 | if ($Rows.Count -ne 37 -or $Tests -ne 66 -or $Failures -ne 0 -or $Errors -ne 0 -or $Skipped -ne 0) { | 실행 의미: 조건·반복·함수의 실행 block을 연다. |
| 46 | throw "W24D1 actual aggregate mismatch classes=$($Rows.Count) tests=$Tests" | 실행 의미: class 이름과 기대 test 수를 exact inventory로 고정한다. |
| 47 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 49 | $Gate = Get-Content -Raw -LiteralPath $GateText | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 50 | foreach ($Token in @('CORE_V1_GATE_GREEN', 'classes=37', 'tests=66', 'failures=0', 'errors=0', 'skipped=0')) { | 실행 의미: class 이름과 기대 test 수를 exact inventory로 고정한다. |
| 51 | if ($Gate -cnotmatch [regex]::Escape($Token)) { | 실행 의미: 조건·반복·함수의 실행 block을 연다. |
| 52 | throw "W24D1 gate marker missing: $Token" | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 53 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 54 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 56 | $ExpectedHash = (Get-FileHash -LiteralPath $ExpectedPath -Algorithm SHA256).Hash.ToLowerInvariant() | 실행 의미: 현재 bytes를 64자리 digest로 evidence에 결박한다. |
| 57 | $GateHash = (Get-FileHash -LiteralPath $GateText -Algorithm SHA256).Hash.ToLowerInvariant() | 실행 의미: 현재 bytes를 64자리 digest로 evidence에 결박한다. |
| 58 | $Lines = @( | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 59 | '# W24 test inventory', | 실행 의미: 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다. |
| 60 | 'status: GREEN', | 실행 의미: W24-D1-primary-evidence-closure.ps1의 다음 검증 또는 설명 단계를 구성한다. |
| 61 | 'source: actual coreV1Gate XML', | 실행 의미: W24-D1-primary-evidence-closure.ps1의 다음 검증 또는 설명 단계를 구성한다. |
| 62 | "classes: $($Rows.Count)", | 실행 의미: class 이름과 기대 test 수를 exact inventory로 고정한다. |
| 63 | "tests: $Tests", | 실행 의미: W24-D1-primary-evidence-closure.ps1의 다음 검증 또는 설명 단계를 구성한다. |
| 64 | "failures: $Failures", | 실행 의미: W24-D1-primary-evidence-closure.ps1의 다음 검증 또는 설명 단계를 구성한다. |
| 65 | "errors: $Errors", | 실행 의미: W24-D1-primary-evidence-closure.ps1의 다음 검증 또는 설명 단계를 구성한다. |
| 66 | "skipped: $Skipped", | 실행 의미: W24-D1-primary-evidence-closure.ps1의 다음 검증 또는 설명 단계를 구성한다. |
| 67 | "expected_sha256: $ExpectedHash", | 실행 의미: 현재 bytes를 64자리 digest로 evidence에 결박한다. |
| 68 | "gate_sha256: $GateHash", | 실행 의미: 현재 bytes를 64자리 digest로 evidence에 결박한다. |
| 69 | '', | 실행 의미: W24-D1-primary-evidence-closure.ps1의 다음 검증 또는 설명 단계를 구성한다. |
| 70 | '| class | tests | failures | errors | skipped | xml_sha256 |', | 실행 의미: 현재 bytes를 64자리 digest로 evidence에 결박한다. |
| 71 | '|---|---:|---:|---:|---:|---|' | 실행 의미: Markdown 표 또는 PowerShell pipeline에서 값을 열이나 다음 명령으로 연결한다. |
| 72 | ) | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 73 | $Lines += @($Rows | Sort-Object class | ForEach-Object { | 실행 의미: 고정 목록의 각 항목에 같은 검사를 반복 적용한다. |
| 74 | "| $($_.class) | $($_.tests) | $($_.failures) | $($_.errors) | $($_.skipped) | $($_.xml_sha256) |" | 실행 의미: 현재 bytes를 64자리 digest로 evidence에 결박한다. |
| 75 | }) | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 77 | $Tmp = "$Artifact.tmp" | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 78 | New-Item -ItemType Directory -Force (Split-Path -Parent $Artifact) | Out-Null | 실행 의미: Markdown 표 또는 PowerShell pipeline에서 값을 열이나 다음 명령으로 연결한다. |
| 79 | $Lines | Set-Content -Encoding utf8 $Tmp | 실행 의미: Markdown 표 또는 PowerShell pipeline에서 값을 열이나 다음 명령으로 연결한다. |
| 80 | $Saved = Get-Content -Raw -LiteralPath $Tmp | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 81 | foreach ($Token in @('source: actual coreV1Gate XML', 'classes: 37', 'tests: 66', 'failures: 0', 'errors: 0', 'skipped: 0', "expected_sha256: $ExpectedHash", "gate_sha256: $GateHash")) { | 실행 의미: class 이름과 기대 test 수를 exact inventory로 고정한다. |
| 82 | if ($Saved -cnotmatch [regex]::Escape($Token)) { | 실행 의미: 조건·반복·함수의 실행 block을 연다. |
| 83 | throw "W24D1 inventory marker missing: $Token" | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 84 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 85 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 86 | Move-Item -Force -LiteralPath $Tmp -Destination $Artifact | 실행 의미: W24-D1-primary-evidence-closure.ps1의 다음 검증 또는 설명 단계를 구성한다. |
| 87 | if (!(Test-Path -LiteralPath $Artifact -PathType Leaf)) { | 실행 의미: 필수 파일이나 경로가 실제로 있는지 확인한다. |
| 88 | throw 'W24D1 atomic inventory move failed' | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 89 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 90 | $Hash = (Get-FileHash -LiteralPath $Artifact -Algorithm SHA256).Hash.ToLowerInvariant() | 실행 의미: 현재 bytes를 64자리 digest로 evidence에 결박한다. |
| 91 | "W24D1_PRIMARY_EVIDENCE_GREEN classes=37 tests=66 failures=0 errors=0 skipped=0 actual_xml=37 sha256=$Hash" | 실행 의미: class 이름과 기대 test 수를 exact inventory로 고정한다. |
STEP 07 / 13
기존 수준의 한 줄 읽기·문법 해부
쉬운 설명 다음에 문법과 실행 순서를 정밀하게 읽습니다.
한 줄로 읽기W24 D1 test inventory — actual XML을 evidence에 원자 저장는 PDF p789의 당일 evidence closure를 가독성 있게 정리해 class별 XML hash와 aggregate를 test-inventory.md에 묶는다.
문법 해부
- .ps1 문법에서 선언·조건·pipeline·block 경계를 먼저 나눈다.
- expected 값과 actual 결과를 같은 이름처럼 보여도 서로 다른 source로 읽는다.
- native exit·row count·hash·사람 판정을 서로 대체하지 않는다.
실행 순서
- 입력 경로·fixture·환경변수·expected 계약을 고정한다.
- source가 실행하는 native process·HTTP·SQL 또는 형식 검사를 따라간다.
- actual 값과 exact marker를 대조하고 실패면 성공 발행 전에 중단한다.
- finally cleanup과 비범위를 evidence에 남긴다.
W24 조각별 정밀 해설
F04-C01 · 원문 1–12줄
- 문법 해부
- .ps1 문법으로 1–12줄의 선언·조건·pipeline·block을 나눈다.
- 실제 값 추적
- actual_xml=37, tests=66, atomic tmp move를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- expected와 actual이 일치하고 owner evidence가 같은 run/hash에 연결되는 경우다.
- 틀린 예·반례
- PDF-only 학습 예시이며 packaged 정본이 아니다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- 파일 존재·문자열·hash·exit0 하나를 의미 Green 전체와 같다고 보지 않는다.
- 하지 않는 일
- PDF-only 학습 예시이며 packaged 정본이 아니다; 고정 숫자만 적은 문서는 통과하지 않는다; 실제 실행 결과를 주장하지 않는다
- 다음 연결
- 다음 조각 또는 F04 evidence 판정으로 상태를 넘긴다.
F04-C02 · 원문 13–24줄
- 문법 해부
- .ps1 문법으로 13–24줄의 선언·조건·pipeline·block을 나눈다.
- 실제 값 추적
- actual_xml=37, tests=66, atomic tmp move를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- expected와 actual이 일치하고 owner evidence가 같은 run/hash에 연결되는 경우다.
- 틀린 예·반례
- PDF-only 학습 예시이며 packaged 정본이 아니다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- 파일 존재·문자열·hash·exit0 하나를 의미 Green 전체와 같다고 보지 않는다.
- 하지 않는 일
- PDF-only 학습 예시이며 packaged 정본이 아니다; 고정 숫자만 적은 문서는 통과하지 않는다; 실제 실행 결과를 주장하지 않는다
- 다음 연결
- 다음 조각 또는 F04 evidence 판정으로 상태를 넘긴다.
F04-C03 · 원문 25–36줄
- 문법 해부
- .ps1 문법으로 25–36줄의 선언·조건·pipeline·block을 나눈다.
- 실제 값 추적
- actual_xml=37, tests=66, atomic tmp move를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- expected와 actual이 일치하고 owner evidence가 같은 run/hash에 연결되는 경우다.
- 틀린 예·반례
- PDF-only 학습 예시이며 packaged 정본이 아니다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- 파일 존재·문자열·hash·exit0 하나를 의미 Green 전체와 같다고 보지 않는다.
- 하지 않는 일
- PDF-only 학습 예시이며 packaged 정본이 아니다; 고정 숫자만 적은 문서는 통과하지 않는다; 실제 실행 결과를 주장하지 않는다
- 다음 연결
- 다음 조각 또는 F04 evidence 판정으로 상태를 넘긴다.
F04-C04 · 원문 37–48줄
- 문법 해부
- .ps1 문법으로 37–48줄의 선언·조건·pipeline·block을 나눈다.
- 실제 값 추적
- actual_xml=37, tests=66, atomic tmp move를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- expected와 actual이 일치하고 owner evidence가 같은 run/hash에 연결되는 경우다.
- 틀린 예·반례
- PDF-only 학습 예시이며 packaged 정본이 아니다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- 파일 존재·문자열·hash·exit0 하나를 의미 Green 전체와 같다고 보지 않는다.
- 하지 않는 일
- PDF-only 학습 예시이며 packaged 정본이 아니다; 고정 숫자만 적은 문서는 통과하지 않는다; 실제 실행 결과를 주장하지 않는다
- 다음 연결
- 다음 조각 또는 F04 evidence 판정으로 상태를 넘긴다.
F04-C05 · 원문 49–60줄
- 문법 해부
- .ps1 문법으로 49–60줄의 선언·조건·pipeline·block을 나눈다.
- 실제 값 추적
- actual_xml=37, tests=66, atomic tmp move를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- expected와 actual이 일치하고 owner evidence가 같은 run/hash에 연결되는 경우다.
- 틀린 예·반례
- PDF-only 학습 예시이며 packaged 정본이 아니다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- 파일 존재·문자열·hash·exit0 하나를 의미 Green 전체와 같다고 보지 않는다.
- 하지 않는 일
- PDF-only 학습 예시이며 packaged 정본이 아니다; 고정 숫자만 적은 문서는 통과하지 않는다; 실제 실행 결과를 주장하지 않는다
- 다음 연결
- 다음 조각 또는 F04 evidence 판정으로 상태를 넘긴다.
F04-C06 · 원문 61–72줄
- 문법 해부
- .ps1 문법으로 61–72줄의 선언·조건·pipeline·block을 나눈다.
- 실제 값 추적
- actual_xml=37, tests=66, atomic tmp move를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- expected와 actual이 일치하고 owner evidence가 같은 run/hash에 연결되는 경우다.
- 틀린 예·반례
- PDF-only 학습 예시이며 packaged 정본이 아니다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- 파일 존재·문자열·hash·exit0 하나를 의미 Green 전체와 같다고 보지 않는다.
- 하지 않는 일
- PDF-only 학습 예시이며 packaged 정본이 아니다; 고정 숫자만 적은 문서는 통과하지 않는다; 실제 실행 결과를 주장하지 않는다
- 다음 연결
- 다음 조각 또는 F04 evidence 판정으로 상태를 넘긴다.
F04-C07 · 원문 73–84줄
- 문법 해부
- .ps1 문법으로 73–84줄의 선언·조건·pipeline·block을 나눈다.
- 실제 값 추적
- actual_xml=37, tests=66, atomic tmp move를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- expected와 actual이 일치하고 owner evidence가 같은 run/hash에 연결되는 경우다.
- 틀린 예·반례
- PDF-only 학습 예시이며 packaged 정본이 아니다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- 파일 존재·문자열·hash·exit0 하나를 의미 Green 전체와 같다고 보지 않는다.
- 하지 않는 일
- PDF-only 학습 예시이며 packaged 정본이 아니다; 고정 숫자만 적은 문서는 통과하지 않는다; 실제 실행 결과를 주장하지 않는다
- 다음 연결
- 다음 조각 또는 F04 evidence 판정으로 상태를 넘긴다.
F04-C08 · 원문 85–91줄
- 문법 해부
- .ps1 문법으로 85–91줄의 선언·조건·pipeline·block을 나눈다.
- 실제 값 추적
- actual_xml=37, tests=66, atomic tmp move를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- expected와 actual이 일치하고 owner evidence가 같은 run/hash에 연결되는 경우다.
- 틀린 예·반례
- PDF-only 학습 예시이며 packaged 정본이 아니다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- 파일 존재·문자열·hash·exit0 하나를 의미 Green 전체와 같다고 보지 않는다.
- 하지 않는 일
- PDF-only 학습 예시이며 packaged 정본이 아니다; 고정 숫자만 적은 문서는 통과하지 않는다; 실제 실행 결과를 주장하지 않는다
- 다음 연결
- 다음 조각 또는 F04 evidence 판정으로 상태를 넘긴다.
실행 순서 — W24 D1 test inventory — actual XML을 evidence에 원자 저장
-
tests=66가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 PDF p789의 당일 evidence closure를 가독성 있게 정리해 class별 XML hash와 aggregate를 test-inventory.md에 묶는다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘고정 숫자만 적은 문서는 통과하지 않는다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 tests=66와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 08 / 13
실제 값 따라가기
같은 입력값이 어느 줄을 지나 어떤 결과가 되는지 추적합니다.
| 순서 | 들어온 값 | 코드가 하는 일 | 나온 값·상태 | 경계 |
|---|---|---|---|---|
| 입력 | actual_xml=37 | source 계약에 대입 | F04 실행/설명 시작 상태 | PDF-only 학습 예시이며 packaged 정본이 아니다 |
| 검증 | tests=66 | expected와 actual 또는 형식 대조 | 통과 또는 첫 mismatch | 고정 숫자만 적은 문서는 통과하지 않는다 |
| 증거 | expected/gate SHA-256 | marker·hash·row를 같은 run에 연결 | 범위가 적힌 evidence 후보 | 실제 실행 결과를 주장하지 않는다 |
실제 값 — W24 D1 test inventory — actual XML을 evidence에 원자 저장
-
atomic tmp move가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 PDF p789의 당일 evidence closure를 가독성 있게 정리해 class별 XML hash와 aggregate를 test-inventory.md에 묶는다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘실제 실행 결과를 주장하지 않는다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 atomic tmp move와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 09 / 13
Gradle·PowerShell·HTTP·PostgreSQL 내부에서 벌어지는 일
Gradle·JUnit XML·PowerShell·HTTP·PostgreSQL·Docker에서 실제로 일어나는 일과 증명 범위를 구분합니다.
W24-D1-primary-evidence-closure.ps1 bytes와 expected 값을 읽는다.
파일 존재만으로 runtime 성공은 아니다.native exit·HTTP status·JUnit XML·DB row·hash 중 이 파일이 소유한 값을 만든다.
PDF-only 학습 예시이며 packaged 정본이 아니다관련 evidence와 사람 의미 검토를 release 후보에 연결한다.
실제 실행 결과를 주장하지 않는다첫 실패 경계 — W24 D1 test inventory — actual XML을 evidence에 원자 저장
-
expected/gate SHA-256가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 PDF p789의 당일 evidence closure를 가독성 있게 정리해 class별 XML hash와 aggregate를 test-inventory.md에 묶는다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘PDF-only 학습 예시이며 packaged 정본이 아니다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 expected/gate SHA-256와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 10 / 13
흔한 착각과 틀린 예
그럴듯하지만 틀린 해석을 반례로 고칩니다.
❌ actual_xml=37 문자열이 source에 있으니 실제 실행도 Green이다.
왜 틀리나 source literal과 runtime 관찰값은 다른 증거다.
바르게 읽기 native exit·actual XML/HTTP/DB evidence를 별도로 확인한다.
반례 script가 실행 전 경로 오류로 멈춰도 literal은 그대로 남는다.
❌ 파일 SHA-256이 있으면 내용의 의미와 사실성도 검증됐다.
왜 틀리나 hash는 동일 bytes만 말한다.
바르게 읽기 schema·수치·질문·근거는 별도 자동 또는 사람 판정을 거친다.
반례 빈 review 질문을 가진 CSV도 안정된 hash를 가진다.
❌ LOCAL_ARTIFACT_VALIDATED는 release Green과 같다.
왜 틀리나 generic validator는 파일 shape만 확인한다.
바르게 읽기 HUMAN_SEMANTIC_REVIEW_REQUIRED를 유지한다.
반례 잘못된 track 점수표도 byte 수 조건은 통과할 수 있다.
❌ 이 파일이 W24 전체 lifecycle을 모두 소유한다.
왜 틀리나 각 source는 Gate·demo·cleanup·사람 review 중 일부만 담당한다.
바르게 읽기 owner와 non-responsibility를 release manifest에서 분리한다.
반례 D4 source audit에는 runtime_claim=false가 명시된다.
❌ 이전 주 Green이나 오래된 log를 현재 commit 결과로 재사용한다.
왜 틀리나 source·commit·actual result가 같은 실행에 묶이지 않는다.
바르게 읽기 release 후보에서 새 evidence와 hash를 만든다.
반례 expected JSON이 바뀌면 예전 XML은 exact inventory를 증명하지 못한다.
STEP 11 / 13
이 코드가 보장하지 않는 것
이 코드가 책임지지 않는 일을 분리합니다.
PDF-only 학습 예시이며 packaged 정본이 아니다
이 책임을 맡는 곳: runtime Gate고정 숫자만 적은 문서는 통과하지 않는다
이 책임을 맡는 곳: external/human review실제 실행 결과를 주장하지 않는다
이 책임을 맡는 곳: release manifestPDF-only 학습 예시이며 packaged 정본이 아니다
이 책임을 맡는 곳: 운영 환경증명하지 않는 범위 — W24 D1 test inventory — actual XML을 evidence에 원자 저장
-
actual_xml=37가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 PDF p789의 당일 evidence closure를 가독성 있게 정리해 class별 XML hash와 aggregate를 test-inventory.md에 묶는다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘고정 숫자만 적은 문서는 통과하지 않는다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 actual_xml=37와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 12 / 13
직접 다시 써보기
뜻 → 조각 → 전체 코드 순서로 다시 씁니다.
1단계 · 뜻부터 복원
- PDF p789의 당일 evidence closure를 가독성 있게 정리해 class별 XML hash와 aggregate를 test-inventory.md에 묶는다.
- 핵심 값은 actual_xml=37, tests=66, atomic tmp move, expected/gate SHA-256다.
2단계 · 코드 조각 재조립
- 1. 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다
- 2. 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다
- 3. 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다
- 4. 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다
- 5. 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다
- 6. 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다
- 8. W24-D1-primary-evidence-closure.ps1의 다음 검증 또는 설명 단계를 구성한다
- 9. W24-D1-primary-evidence-closure.ps1의 다음 검증 또는 설명 단계를 구성한다
3단계 · 파일 전체 다시 쓰기
illustrative/powershell/W24-D1-primary-evidence-closure.ps1을 새 파일에 다시 쓰고 expected·actual·실패·cleanup·비범위를 주석으로 표시한다.
자가 점검
- 비어 있지 않은 모든 source 줄을 한 번씩 읽었나?
- source shape와 runtime Green을 분리했나?
- 사람 검토·외부 상태를 자동 성공으로 꾸미지 않았나?
- 첫 실패와 cleanup 책임을 설명할 수 있나?
STEP 13 / 13
전체 원본 source
감사로 고정한 전체 source를 가감 없이 확인합니다.
학습용 예시 전체 확인하기 · 정본 답안 아님
# W24 PDF p789에서 제공한 당일 Gate를 읽기 좋게 정리한 학습용 예시다.
# packaged reference source가 아니며, 실제 Gradle/JUnit 실행 결과도 아니다.
$PRIMARY_PRODUCER = 1
$Artifact = Join-Path $LearnerRoot 'evidence\w24\test-inventory.md'
$Verifier = Join-Path $ReferenceRoot 'scripts\verify-core-v1-gate.ps1'
$GateText = Join-Path $LearnerRoot 'evidence\w24\core-v1-gate.txt'
& powershell.exe -NoProfile -ExecutionPolicy Bypass -File $Verifier `
-ProjectRoot $LearnerRoot -EvidencePath $GateText
if ($LASTEXITCODE -ne 0) {
throw "W24D1 core verifier native exit=$LASTEXITCODE"
}
$ExpectedPath = Join-Path $ReferenceRoot 'learning_stages\w24\overlay\core-v1-expected.json'
$Expected = Get-Content -Raw -LiteralPath $ExpectedPath | ConvertFrom-Json
$ResultDir = Join-Path $LearnerRoot 'build\test-results\coreV1Gate'
$Rows = @(Get-ChildItem -LiteralPath $ResultDir -Filter 'TEST-*.xml' -File | ForEach-Object {
[xml]$Xml = Get-Content -Raw -LiteralPath $_.FullName
[pscustomobject]@{
class = [string]$Xml.testsuite.name
tests = [int]$Xml.testsuite.tests
failures = [int]$Xml.testsuite.failures
errors = [int]$Xml.testsuite.errors
skipped = [int]$Xml.testsuite.skipped
xml_sha256 = (Get-FileHash -LiteralPath $_.FullName -Algorithm SHA256).Hash.ToLowerInvariant()
}
})
$ExpectedNames = @($Expected.classes.psobject.Properties.Name | Sort-Object)
$ActualNames = @($Rows.class | Sort-Object -Unique)
if (Compare-Object $ExpectedNames $ActualNames) {
throw 'W24D1 actual XML class set differs from canonical expectation'
}
foreach ($Row in $Rows) {
$ExpectedTests = [int]$Expected.classes.psobject.Properties[$Row.class].Value
if ($Row.tests -ne $ExpectedTests -or $Row.failures -ne 0 -or $Row.errors -ne 0 -or $Row.skipped -ne 0) {
throw "W24D1 class/count/status mismatch: $($Row.class)"
}
}
$Tests = ($Rows | Measure-Object tests -Sum).Sum
$Failures = ($Rows | Measure-Object failures -Sum).Sum
$Errors = ($Rows | Measure-Object errors -Sum).Sum
$Skipped = ($Rows | Measure-Object skipped -Sum).Sum
if ($Rows.Count -ne 37 -or $Tests -ne 66 -or $Failures -ne 0 -or $Errors -ne 0 -or $Skipped -ne 0) {
throw "W24D1 actual aggregate mismatch classes=$($Rows.Count) tests=$Tests"
}
$Gate = Get-Content -Raw -LiteralPath $GateText
foreach ($Token in @('CORE_V1_GATE_GREEN', 'classes=37', 'tests=66', 'failures=0', 'errors=0', 'skipped=0')) {
if ($Gate -cnotmatch [regex]::Escape($Token)) {
throw "W24D1 gate marker missing: $Token"
}
}
$ExpectedHash = (Get-FileHash -LiteralPath $ExpectedPath -Algorithm SHA256).Hash.ToLowerInvariant()
$GateHash = (Get-FileHash -LiteralPath $GateText -Algorithm SHA256).Hash.ToLowerInvariant()
$Lines = @(
'# W24 test inventory',
'status: GREEN',
'source: actual coreV1Gate XML',
"classes: $($Rows.Count)",
"tests: $Tests",
"failures: $Failures",
"errors: $Errors",
"skipped: $Skipped",
"expected_sha256: $ExpectedHash",
"gate_sha256: $GateHash",
'',
'| class | tests | failures | errors | skipped | xml_sha256 |',
'|---|---:|---:|---:|---:|---|'
)
$Lines += @($Rows | Sort-Object class | ForEach-Object {
"| $($_.class) | $($_.tests) | $($_.failures) | $($_.errors) | $($_.skipped) | $($_.xml_sha256) |"
})
$Tmp = "$Artifact.tmp"
New-Item -ItemType Directory -Force (Split-Path -Parent $Artifact) | Out-Null
$Lines | Set-Content -Encoding utf8 $Tmp
$Saved = Get-Content -Raw -LiteralPath $Tmp
foreach ($Token in @('source: actual coreV1Gate XML', 'classes: 37', 'tests: 66', 'failures: 0', 'errors: 0', 'skipped: 0', "expected_sha256: $ExpectedHash", "gate_sha256: $GateHash")) {
if ($Saved -cnotmatch [regex]::Escape($Token)) {
throw "W24D1 inventory marker missing: $Token"
}
}
Move-Item -Force -LiteralPath $Tmp -Destination $Artifact
if (!(Test-Path -LiteralPath $Artifact -PathType Leaf)) {
throw 'W24D1 atomic inventory move failed'
}
$Hash = (Get-FileHash -LiteralPath $Artifact -Algorithm SHA256).Hash.ToLowerInvariant()
"W24D1_PRIMARY_EVIDENCE_GREEN classes=37 tests=66 failures=0 errors=0 skipped=0 actual_xml=37 sha256=$Hash"
05W24 D2 architecture pack — 정상·실패·중복 sequence와 수동 검토 경계
illustrative/markdown/W24-D2-architecture-pack.md
학습용 예시 · PDF template/validator · 정본 답안 아님 · 학습용 예시 · 정본 답안 아님 · W24-F0523줄 연결23줄 번역3 chunks
W24 D2 architecture pack — 정상·실패·중복 sequence와 수동 검토 경계
illustrative/markdown/W24-D2-architecture-pack.md
학습용 예시 · PDF template/validator · 정본 답안 아님 · 학습용 예시 · 정본 답안 아님 · W24-F05STEP 01 / 13
오늘 이 코드에서 해결할 문제
무엇을 이해해야 하는지 질문부터 잡습니다.
ERD와 세 transaction 흐름에 atomic claim, sorted locks, rollback, replay를 배치하고 파일 hash 검사와 의미 검토를 분리한다.
- from=10000은 어느 source와 실제 결과에서 확인해야 할까?
- 첫 실패를 만드는 조건과 fail-closed 지점은 어디일까?
- 왜 ‘architecture-pack.pdf 완성본이 아니다’를 별도 경계로 남겨야 할까?
from=10000to=5000amount=1000same payload replaydifferent hash=409왜 필요한가 — W24 D2 architecture pack — 정상·실패·중복 sequence와 수동 검토 경계
-
from=10000가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 ERD와 세 transaction 흐름에 atomic claim, sorted locks, rollback, replay를 배치하고 파일 hash 검사와 의미 검토를 분리한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘architecture-pack.pdf 완성본이 아니다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 from=10000와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 02 / 13
아주 짧게: 이 코드는 왜 필요할까?
웹소설 대신 이 코드가 필요한 이유만 두 문단으로 쉽게 봅니다.
새 기능을 멈춘 팀이 코드·test·문서·demo를 같은 release 후보에 묶어 하나씩 검수한다.
검수 도장이 붙은 공통 거래 코어 출고 상자
이 파일은 ERD와 세 transaction 흐름에 atomic claim, sorted locks, rollback, replay를 배치하고 파일 hash 검사와 의미 검토를 분리한다. 눈으로 읽을 때는 각 줄을 검수표 한 칸처럼 보고, 입력과 다음 상태를 놓치지 않는다.
마지막 도장은 source shape와 실제 runtime·사람 검토를 구분한 뒤에만 찍는다. 특히 architecture-pack.pdf 완성본이 아니다
딱 여기까지만 비유는 실행 순서를 돕지만 실제 Gradle·Docker·DB·사람 review를 대신하지 않는다.
STEP 03 / 13
초등학생도 이해하는 설명
생활 비유와 실제 코드의 경계를 함께 확인합니다.
값 1: from=10000
이 파일에서 계속 확인할 고정 단서가 from=10000다.
- 코드 연결
F05 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- architecture-pack.pdf 완성본이 아니다
값 2: to=5000
이 파일에서 계속 확인할 고정 단서가 to=5000다.
- 코드 연결
F05 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- MANUAL_REVIEW_REQUIRED는 Green이 아니다
값 3: amount=1000
이 파일에서 계속 확인할 고정 단서가 amount=1000다.
- 코드 연결
F05 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- 실은행 GL·HA는 범위 밖이다
값 4: same payload replay
이 파일에서 계속 확인할 고정 단서가 same payload replay다.
- 코드 연결
F05 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- architecture-pack.pdf 완성본이 아니다
값 5: different hash=409
이 파일에서 계속 확인할 고정 단서가 different hash=409다.
- 코드 연결
F05 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- MANUAL_REVIEW_REQUIRED는 Green이 아니다
STEP 04 / 13
비유 ↔ 코드 전체 연결표
감사 규칙상 연결 대상인 원본 23줄을 빠짐없이 연결합니다.
| 줄 | 정확한 원본 줄 | STARRY 비유 | 실제 뜻·입력·결과·한계 |
|---|---|---|---|
| 1줄F05-L01 | # W24 D2 architecture pack 학습 골격 |
출고표 1번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다.
|
| 3줄F05-L03 | > PDF p792의 TEMPLATE와 validator를 한 파일에 모은 학습용 예시다. |
출고표 3번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W24-D2-architecture-pack.md의 다음 검증 또는 설명 단계를 구성한다.
|
| 5줄F05-L05 | ## Sequence 핵심 |
출고표 5번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다.
|
| 7줄F05-L07 | Request -> RequestIdFilter -> Authorization -> AtomicClaim |
출고표 7번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 인증 header를 runtime에서 만들되 evidence에 원문 비밀을 남기지 않는다.
|
| 8줄F05-L08 | owner -> sorted account locks -> debit/ |
출고표 8번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W24-D2-architecture-pack.md의 다음 검증 또는 설명 단계를 구성한다.
|
| 9줄F05-L09 | existing same hash COMPLETE -> replay stored response |
출고표 9번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W24-D2-architecture-pack.md의 다음 검증 또는 설명 단계를 구성한다.
|
| 10줄F05-L10 | different hash -> 409 no state change |
출고표 10번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W24-D2-architecture-pack.md의 다음 검증 또는 설명 단계를 구성한다.
|
| 12줄F05-L12 | ## 학습자 산출물 검사 |
출고표 12번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다.
|
| 14줄F05-L14 | $Artifact = |
출고표 14번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 15줄F05-L15 | if ( |
출고표 15번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 필수 파일이나 경로가 실제로 있는지 확인한다.
|
| 16줄F05-L16 | throw "learner artifact missing: |
출고표 16번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 17줄F05-L17 | } |
출고표 17번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 18줄F05-L18 | $Item = |
출고표 18번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 19줄F05-L19 | if ( |
출고표 19번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 조건·반복·함수의 실행 block을 연다.
|
| 20줄F05-L20 | throw "artifact is too small to support the claim: |
출고표 20번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 21줄F05-L21 | } |
출고표 21번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 22줄F05-L22 | $Hash = |
출고표 22번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 현재 bytes를 64자리 digest로 evidence에 결박한다.
|
| 23줄F05-L23 | "MANUAL_REVIEW_REQUIRED W24D2 bytes= |
출고표 23번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 자동 검사가 내용의 의미를 판정하지 못해 사람 검토가 남았음을 표시한다.
|
| 25줄F05-L25 | ## 사람 확인이 남는 이유 |
출고표 25번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다.
|
| 27줄F05-L27 | - 이 검사는 파일 존재·최소 크기·hash만 본다. |
출고표 27번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W24-D2-architecture-pack.md의 다음 검증 또는 설명 단계를 구성한다.
|
| 28줄F05-L28 | - ERD가 실제 V001/ |
출고표 28번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W24-D2-architecture-pack.md의 다음 검증 또는 설명 단계를 구성한다.
|
| 29줄F05-L29 | - 정상·중간 실패·동시 중복 sequence의 lock order, |
출고표 29번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W24-D2-architecture-pack.md의 다음 검증 또는 설명 단계를 구성한다.
|
| 30줄F05-L30 | - 실은행 GL, |
출고표 30번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W24-D2-architecture-pack.md의 다음 검증 또는 설명 단계를 구성한다.
|
STEP 05 / 13
원본 코드 조각
원본을 3개 의미 조각으로 나누어 그대로 확인합니다.
파일을 한꺼번에 외우지 않고 실행 의미가 이어지는 작은 조각으로 봅니다. 아래 코드는 prompt·fixture·가정을 밝힌 학습용 예시 source이며, 제공 정본 답안이 아닙니다.
# W24 D2 architecture pack 학습 골격
> PDF p792의 TEMPLATE와 validator를 한 파일에 모은 학습용 예시다. 완성 architecture-pack.pdf도, 사람 의미 검토 결과도 아니다.
## Sequence 핵심
Request -> RequestIdFilter -> Authorization -> AtomicClaim
owner -> sorted account locks -> debit/credit -> ledger pair -> COMPLETE -> COMMIT -> response
existing same hash COMPLETE -> replay stored response
different hash -> 409 no state change
## 학습자 산출물 검사
$Artifact = Join-Path $LearnerRoot 'evidence\w24\architecture-pack.pdf'
if (!(Test-Path -LiteralPath $Artifact -PathType Leaf)) {
throw "learner artifact missing: $Artifact"
}
$Item = Get-Item -LiteralPath $Artifact
if ($Item.Length -lt 128) {
throw "artifact is too small to support the claim: bytes=$($Item.Length)"
}
$Hash = (Get-FileHash -LiteralPath $Artifact -Algorithm SHA256).Hash.ToLowerInvariant()
"MANUAL_REVIEW_REQUIRED W24D2 bytes=$($Item.Length) sha256=$Hash"
## 사람 확인이 남는 이유
- 이 검사는 파일 존재·최소 크기·hash만 본다.
- ERD가 실제 V001/V002+ migration과 같은지 자동으로 증명하지 않는다.
- 정상·중간 실패·동시 중복 sequence의 lock order, atomic claim, commit/rollback, replay 의미는 사람이 대조한다.
- 실은행 GL, 결제망, HA, 운영 용량은 이 산출물의 범위 밖이다.
STEP 06 / 13
코드 한 줄씩 한국어로 번역
비어 있지 않은 23줄을 모두 한국어로 옮깁니다.
비어 있지 않은 원본 줄은 하나도 생략하지 않습니다.
| 줄 | 원본 | 한국어 번역 |
|---|---|---|
| 1 | # W24 D2 architecture pack 학습 골격 | 문서 의미: 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다. |
| 3 | > PDF p792의 TEMPLATE와 validator를 한 파일에 모은 학습용 예시다. 완성 architecture-pack.pdf도, 사람 의미 검토 결과도 아니다. | 문서 의미: W24-D2-architecture-pack.md의 다음 검증 또는 설명 단계를 구성한다. |
| 5 | ## Sequence 핵심 | 문서 의미: 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다. |
| 7 | Request -> RequestIdFilter -> Authorization -> AtomicClaim | 문서 의미: 인증 header를 runtime에서 만들되 evidence에 원문 비밀을 남기지 않는다. |
| 8 | owner -> sorted account locks -> debit/credit -> ledger pair -> COMPLETE -> COMMIT -> response | 문서 의미: W24-D2-architecture-pack.md의 다음 검증 또는 설명 단계를 구성한다. |
| 9 | existing same hash COMPLETE -> replay stored response | 문서 의미: W24-D2-architecture-pack.md의 다음 검증 또는 설명 단계를 구성한다. |
| 10 | different hash -> 409 no state change | 문서 의미: W24-D2-architecture-pack.md의 다음 검증 또는 설명 단계를 구성한다. |
| 12 | ## 학습자 산출물 검사 | 문서 의미: 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다. |
| 14 | $Artifact = Join-Path $LearnerRoot 'evidence\w24\architecture-pack.pdf' | 문서 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 15 | if (!(Test-Path -LiteralPath $Artifact -PathType Leaf)) { | 문서 의미: 필수 파일이나 경로가 실제로 있는지 확인한다. |
| 16 | throw "learner artifact missing: $Artifact" | 문서 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 17 | } | 문서 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 18 | $Item = Get-Item -LiteralPath $Artifact | 문서 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 19 | if ($Item.Length -lt 128) { | 문서 의미: 조건·반복·함수의 실행 block을 연다. |
| 20 | throw "artifact is too small to support the claim: bytes=$($Item.Length)" | 문서 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 21 | } | 문서 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 22 | $Hash = (Get-FileHash -LiteralPath $Artifact -Algorithm SHA256).Hash.ToLowerInvariant() | 문서 의미: 현재 bytes를 64자리 digest로 evidence에 결박한다. |
| 23 | "MANUAL_REVIEW_REQUIRED W24D2 bytes=$($Item.Length) sha256=$Hash" | 문서 의미: 자동 검사가 내용의 의미를 판정하지 못해 사람 검토가 남았음을 표시한다. |
| 25 | ## 사람 확인이 남는 이유 | 문서 의미: 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다. |
| 27 | - 이 검사는 파일 존재·최소 크기·hash만 본다. | 문서 의미: W24-D2-architecture-pack.md의 다음 검증 또는 설명 단계를 구성한다. |
| 28 | - ERD가 실제 V001/V002+ migration과 같은지 자동으로 증명하지 않는다. | 문서 의미: W24-D2-architecture-pack.md의 다음 검증 또는 설명 단계를 구성한다. |
| 29 | - 정상·중간 실패·동시 중복 sequence의 lock order, atomic claim, commit/rollback, replay 의미는 사람이 대조한다. | 문서 의미: W24-D2-architecture-pack.md의 다음 검증 또는 설명 단계를 구성한다. |
| 30 | - 실은행 GL, 결제망, HA, 운영 용량은 이 산출물의 범위 밖이다. | 문서 의미: W24-D2-architecture-pack.md의 다음 검증 또는 설명 단계를 구성한다. |
STEP 07 / 13
기존 수준의 한 줄 읽기·문법 해부
쉬운 설명 다음에 문법과 실행 순서를 정밀하게 읽습니다.
한 줄로 읽기W24 D2 architecture pack — 정상·실패·중복 sequence와 수동 검토 경계는 ERD와 세 transaction 흐름에 atomic claim, sorted locks, rollback, replay를 배치하고 파일 hash 검사와 의미 검토를 분리한다.
문법 해부
- .md 문법에서 선언·조건·pipeline·block 경계를 먼저 나눈다.
- expected 값과 actual 결과를 같은 이름처럼 보여도 서로 다른 source로 읽는다.
- native exit·row count·hash·사람 판정을 서로 대체하지 않는다.
실행 순서
- 입력 경로·fixture·환경변수·expected 계약을 고정한다.
- source가 실행하는 native process·HTTP·SQL 또는 형식 검사를 따라간다.
- actual 값과 exact marker를 대조하고 실패면 성공 발행 전에 중단한다.
- finally cleanup과 비범위를 evidence에 남긴다.
W24 조각별 정밀 해설
F05-C01 · 원문 1–12줄
- 문법 해부
- .md 문법으로 1–12줄의 선언·조건·pipeline·block을 나눈다.
- 실제 값 추적
- from=10000, to=5000, amount=1000를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- expected와 actual이 일치하고 owner evidence가 같은 run/hash에 연결되는 경우다.
- 틀린 예·반례
- architecture-pack.pdf 완성본이 아니다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- 파일 존재·문자열·hash·exit0 하나를 의미 Green 전체와 같다고 보지 않는다.
- 하지 않는 일
- architecture-pack.pdf 완성본이 아니다; MANUAL_REVIEW_REQUIRED는 Green이 아니다; 실은행 GL·HA는 범위 밖이다
- 다음 연결
- 다음 조각 또는 F05 evidence 판정으로 상태를 넘긴다.
F05-C02 · 원문 13–24줄
- 문법 해부
- .md 문법으로 13–24줄의 선언·조건·pipeline·block을 나눈다.
- 실제 값 추적
- from=10000, to=5000, amount=1000를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- expected와 actual이 일치하고 owner evidence가 같은 run/hash에 연결되는 경우다.
- 틀린 예·반례
- architecture-pack.pdf 완성본이 아니다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- 파일 존재·문자열·hash·exit0 하나를 의미 Green 전체와 같다고 보지 않는다.
- 하지 않는 일
- architecture-pack.pdf 완성본이 아니다; MANUAL_REVIEW_REQUIRED는 Green이 아니다; 실은행 GL·HA는 범위 밖이다
- 다음 연결
- 다음 조각 또는 F05 evidence 판정으로 상태를 넘긴다.
F05-C03 · 원문 25–30줄
- 문법 해부
- .md 문법으로 25–30줄의 선언·조건·pipeline·block을 나눈다.
- 실제 값 추적
- from=10000, to=5000, amount=1000를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- expected와 actual이 일치하고 owner evidence가 같은 run/hash에 연결되는 경우다.
- 틀린 예·반례
- architecture-pack.pdf 완성본이 아니다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- 파일 존재·문자열·hash·exit0 하나를 의미 Green 전체와 같다고 보지 않는다.
- 하지 않는 일
- architecture-pack.pdf 완성본이 아니다; MANUAL_REVIEW_REQUIRED는 Green이 아니다; 실은행 GL·HA는 범위 밖이다
- 다음 연결
- 다음 조각 또는 F05 evidence 판정으로 상태를 넘긴다.
실행 순서 — W24 D2 architecture pack — 정상·실패·중복 sequence와 수동 검토 경계
-
to=5000가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 ERD와 세 transaction 흐름에 atomic claim, sorted locks, rollback, replay를 배치하고 파일 hash 검사와 의미 검토를 분리한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘MANUAL_REVIEW_REQUIRED는 Green이 아니다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 to=5000와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 08 / 13
실제 값 따라가기
같은 입력값이 어느 줄을 지나 어떤 결과가 되는지 추적합니다.
| 순서 | 들어온 값 | 코드가 하는 일 | 나온 값·상태 | 경계 |
|---|---|---|---|---|
| 입력 | from=10000 | source 계약에 대입 | F05 실행/설명 시작 상태 | architecture-pack.pdf 완성본이 아니다 |
| 검증 | to=5000 | expected와 actual 또는 형식 대조 | 통과 또는 첫 mismatch | MANUAL_REVIEW_REQUIRED는 Green이 아니다 |
| 증거 | different hash=409 | marker·hash·row를 같은 run에 연결 | 범위가 적힌 evidence 후보 | 실은행 GL·HA는 범위 밖이다 |
실제 값 — W24 D2 architecture pack — 정상·실패·중복 sequence와 수동 검토 경계
-
amount=1000가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 ERD와 세 transaction 흐름에 atomic claim, sorted locks, rollback, replay를 배치하고 파일 hash 검사와 의미 검토를 분리한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘실은행 GL·HA는 범위 밖이다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 amount=1000와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 09 / 13
Gradle·PowerShell·HTTP·PostgreSQL 내부에서 벌어지는 일
Gradle·JUnit XML·PowerShell·HTTP·PostgreSQL·Docker에서 실제로 일어나는 일과 증명 범위를 구분합니다.
W24-D2-architecture-pack.md bytes와 expected 값을 읽는다.
파일 존재만으로 runtime 성공은 아니다.native exit·HTTP status·JUnit XML·DB row·hash 중 이 파일이 소유한 값을 만든다.
architecture-pack.pdf 완성본이 아니다관련 evidence와 사람 의미 검토를 release 후보에 연결한다.
실은행 GL·HA는 범위 밖이다첫 실패 경계 — W24 D2 architecture pack — 정상·실패·중복 sequence와 수동 검토 경계
-
same payload replay가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 ERD와 세 transaction 흐름에 atomic claim, sorted locks, rollback, replay를 배치하고 파일 hash 검사와 의미 검토를 분리한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘architecture-pack.pdf 완성본이 아니다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 same payload replay와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 10 / 13
흔한 착각과 틀린 예
그럴듯하지만 틀린 해석을 반례로 고칩니다.
❌ from=10000 문자열이 source에 있으니 실제 실행도 Green이다.
왜 틀리나 source literal과 runtime 관찰값은 다른 증거다.
바르게 읽기 native exit·actual XML/HTTP/DB evidence를 별도로 확인한다.
반례 script가 실행 전 경로 오류로 멈춰도 literal은 그대로 남는다.
❌ 파일 SHA-256이 있으면 내용의 의미와 사실성도 검증됐다.
왜 틀리나 hash는 동일 bytes만 말한다.
바르게 읽기 schema·수치·질문·근거는 별도 자동 또는 사람 판정을 거친다.
반례 빈 review 질문을 가진 CSV도 안정된 hash를 가진다.
❌ LOCAL_ARTIFACT_VALIDATED는 release Green과 같다.
왜 틀리나 generic validator는 파일 shape만 확인한다.
바르게 읽기 HUMAN_SEMANTIC_REVIEW_REQUIRED를 유지한다.
반례 잘못된 track 점수표도 byte 수 조건은 통과할 수 있다.
❌ 이 파일이 W24 전체 lifecycle을 모두 소유한다.
왜 틀리나 각 source는 Gate·demo·cleanup·사람 review 중 일부만 담당한다.
바르게 읽기 owner와 non-responsibility를 release manifest에서 분리한다.
반례 D4 source audit에는 runtime_claim=false가 명시된다.
❌ 이전 주 Green이나 오래된 log를 현재 commit 결과로 재사용한다.
왜 틀리나 source·commit·actual result가 같은 실행에 묶이지 않는다.
바르게 읽기 release 후보에서 새 evidence와 hash를 만든다.
반례 expected JSON이 바뀌면 예전 XML은 exact inventory를 증명하지 못한다.
STEP 11 / 13
이 코드가 보장하지 않는 것
이 코드가 책임지지 않는 일을 분리합니다.
architecture-pack.pdf 완성본이 아니다
이 책임을 맡는 곳: runtime GateMANUAL_REVIEW_REQUIRED는 Green이 아니다
이 책임을 맡는 곳: external/human review실은행 GL·HA는 범위 밖이다
이 책임을 맡는 곳: release manifestarchitecture-pack.pdf 완성본이 아니다
이 책임을 맡는 곳: 운영 환경증명하지 않는 범위 — W24 D2 architecture pack — 정상·실패·중복 sequence와 수동 검토 경계
-
different hash=409가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 ERD와 세 transaction 흐름에 atomic claim, sorted locks, rollback, replay를 배치하고 파일 hash 검사와 의미 검토를 분리한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘MANUAL_REVIEW_REQUIRED는 Green이 아니다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 different hash=409와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 12 / 13
직접 다시 써보기
뜻 → 조각 → 전체 코드 순서로 다시 씁니다.
1단계 · 뜻부터 복원
- ERD와 세 transaction 흐름에 atomic claim, sorted locks, rollback, replay를 배치하고 파일 hash 검사와 의미 검토를 분리한다.
- 핵심 값은 from=10000, to=5000, amount=1000, same payload replay, different hash=409다.
2단계 · 코드 조각 재조립
- 1. 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다
- 3. W24-D2-architecture-pack.md의 다음 검증 또는 설명 단계를 구성한다
- 5. 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다
- 7. 인증 header를 runtime에서 만들되 evidence에 원문 비밀을 남기지 않는다
- 8. W24-D2-architecture-pack.md의 다음 검증 또는 설명 단계를 구성한다
- 9. W24-D2-architecture-pack.md의 다음 검증 또는 설명 단계를 구성한다
- 10. W24-D2-architecture-pack.md의 다음 검증 또는 설명 단계를 구성한다
- 12. 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다
3단계 · 파일 전체 다시 쓰기
illustrative/markdown/W24-D2-architecture-pack.md을 새 파일에 다시 쓰고 expected·actual·실패·cleanup·비범위를 주석으로 표시한다.
자가 점검
- 비어 있지 않은 모든 source 줄을 한 번씩 읽었나?
- source shape와 runtime Green을 분리했나?
- 사람 검토·외부 상태를 자동 성공으로 꾸미지 않았나?
- 첫 실패와 cleanup 책임을 설명할 수 있나?
STEP 13 / 13
전체 원본 source
감사로 고정한 전체 source를 가감 없이 확인합니다.
학습용 예시 전체 확인하기 · 정본 답안 아님
# W24 D2 architecture pack 학습 골격
> PDF p792의 TEMPLATE와 validator를 한 파일에 모은 학습용 예시다. 완성 architecture-pack.pdf도, 사람 의미 검토 결과도 아니다.
## Sequence 핵심
Request -> RequestIdFilter -> Authorization -> AtomicClaim
owner -> sorted account locks -> debit/credit -> ledger pair -> COMPLETE -> COMMIT -> response
existing same hash COMPLETE -> replay stored response
different hash -> 409 no state change
## 학습자 산출물 검사
$Artifact = Join-Path $LearnerRoot 'evidence\w24\architecture-pack.pdf'
if (!(Test-Path -LiteralPath $Artifact -PathType Leaf)) {
throw "learner artifact missing: $Artifact"
}
$Item = Get-Item -LiteralPath $Artifact
if ($Item.Length -lt 128) {
throw "artifact is too small to support the claim: bytes=$($Item.Length)"
}
$Hash = (Get-FileHash -LiteralPath $Artifact -Algorithm SHA256).Hash.ToLowerInvariant()
"MANUAL_REVIEW_REQUIRED W24D2 bytes=$($Item.Length) sha256=$Hash"
## 사람 확인이 남는 이유
- 이 검사는 파일 존재·최소 크기·hash만 본다.
- ERD가 실제 V001/V002+ migration과 같은지 자동으로 증명하지 않는다.
- 정상·중간 실패·동시 중복 sequence의 lock order, atomic claim, commit/rollback, replay 의미는 사람이 대조한다.
- 실은행 GL, 결제망, HA, 운영 용량은 이 산출물의 범위 밖이다.
06W24 D3 README — 위험·선택·검증·결과·한계 연결
illustrative/markdown/W24-D3-readme-evidence.md
학습용 예시 · PDF template/validator · 정본 답안 아님 · 학습용 예시 · 정본 답안 아님 · W24-F0631줄 연결31줄 번역4 chunks
W24 D3 README — 위험·선택·검증·결과·한계 연결
illustrative/markdown/W24-D3-readme-evidence.md
학습용 예시 · PDF template/validator · 정본 답안 아님 · 학습용 예시 · 정본 답안 아님 · W24-F06STEP 01 / 13
오늘 이 코드에서 해결할 문제
무엇을 이해해야 하는지 질문부터 잡습니다.
기능 나열 대신 일곱 위험을 evidence path와 test envelope에 연결하는 README 골격과 형식 validator를 보여 준다.
- SQLSTATE 40P01은 어느 source와 실제 결과에서 확인해야 할까?
- 첫 실패를 만드는 조건과 fail-closed 지점은 어디일까?
- 왜 ‘학습자 README 완성본이 아니다’를 별도 경계로 남겨야 할까?
SQLSTATE 40P01SortedLockTransferIT100 reverse runsLOCAL_ARTIFACT_VALIDATED왜 필요한가 — W24 D3 README — 위험·선택·검증·결과·한계 연결
-
SQLSTATE 40P01가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 기능 나열 대신 일곱 위험을 evidence path와 test envelope에 연결하는 README 골격과 형식 validator를 보여 준다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘학습자 README 완성본이 아니다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 SQLSTATE 40P01와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 02 / 13
아주 짧게: 이 코드는 왜 필요할까?
웹소설 대신 이 코드가 필요한 이유만 두 문단으로 쉽게 봅니다.
새 기능을 멈춘 팀이 코드·test·문서·demo를 같은 release 후보에 묶어 하나씩 검수한다.
검수 도장이 붙은 공통 거래 코어 출고 상자
이 파일은 기능 나열 대신 일곱 위험을 evidence path와 test envelope에 연결하는 README 골격과 형식 validator를 보여 준다. 눈으로 읽을 때는 각 줄을 검수표 한 칸처럼 보고, 입력과 다음 상태를 놓치지 않는다.
마지막 도장은 source shape와 실제 runtime·사람 검토를 구분한 뒤에만 찍는다. 특히 학습자 README 완성본이 아니다
딱 여기까지만 비유는 실행 순서를 돕지만 실제 Gradle·Docker·DB·사람 review를 대신하지 않는다.
STEP 03 / 13
초등학생도 이해하는 설명
생활 비유와 실제 코드의 경계를 함께 확인합니다.
값 1: SQLSTATE 40P01
이 파일에서 계속 확인할 고정 단서가 SQLSTATE 40P01다.
- 코드 연결
F06 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- 학습자 README 완성본이 아니다
값 2: SortedLockTransferIT
이 파일에서 계속 확인할 고정 단서가 SortedLockTransferIT다.
- 코드 연결
F06 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- hash는 내용의 진실성을 증명하지 않는다
값 3: 100 reverse runs
이 파일에서 계속 확인할 고정 단서가 100 reverse runs다.
- 코드 연결
F06 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- 운영 용량 보장이 아니다
값 4: LOCAL_ARTIFACT_VALIDATED
이 파일에서 계속 확인할 고정 단서가 LOCAL_ARTIFACT_VALIDATED다.
- 코드 연결
F06 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- 학습자 README 완성본이 아니다
STEP 04 / 13
비유 ↔ 코드 전체 연결표
감사 규칙상 연결 대상인 원본 31줄을 빠짐없이 연결합니다.
| 줄 | 정확한 원본 줄 | STARRY 비유 | 실제 뜻·입력·결과·한계 |
|---|---|---|---|
| 1줄F06-L01 | # W24 D3 README 학습 골격 |
출고표 1번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다.
|
| 3줄F06-L03 | > PDF p794–795의 TEMPLATE와 validator를 한 파일에 모은 학습용 예시다. |
출고표 3번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W24-D3-readme-evidence.md의 다음 검증 또는 설명 단계를 구성한다.
|
| 5줄F06-L05 | ## Risk: |
출고표 5번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다.
|
| 7줄F06-L07 | - Failure before: |
출고표 7번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W24-D3-readme-evidence.md의 다음 검증 또는 설명 단계를 구성한다.
|
| 8줄F06-L08 | - Choice: |
출고표 8번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W24-D3-readme-evidence.md의 다음 검증 또는 설명 단계를 구성한다.
|
| 9줄F06-L09 | - Verification: |
출고표 9번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W24-D3-readme-evidence.md의 다음 검증 또는 설명 단계를 구성한다.
|
| 10줄F06-L10 | - Result: |
출고표 10번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W24-D3-readme-evidence.md의 다음 검증 또는 설명 단계를 구성한다.
|
| 11줄F06-L11 | - Limitation: |
출고표 11번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W24-D3-readme-evidence.md의 다음 검증 또는 설명 단계를 구성한다.
|
| 13줄F06-L13 | ## 학습자 산출물 검사 |
출고표 13번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다.
|
| 15줄F06-L15 | $Artifact = |
출고표 15번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 16줄F06-L16 | if ( |
출고표 16번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 필수 파일이나 경로가 실제로 있는지 확인한다.
|
| 17줄F06-L17 | throw "learner artifact missing: |
출고표 17번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 18줄F06-L18 | } |
출고표 18번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 19줄F06-L19 | $Item = |
출고표 19번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 20줄F06-L20 | if ( |
출고표 20번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 조건·반복·함수의 실행 block을 연다.
|
| 21줄F06-L21 | throw "artifact is too small to support the claim: |
출고표 21번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 22줄F06-L22 | } |
출고표 22번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 23줄F06-L23 | $Text = |
출고표 23번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 24줄F06-L24 | if ( |
출고표 24번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 Markdown 표 또는 PowerShell pipeline에서 값을 열이나 다음 명령으로 연결한다.
|
| 25줄F06-L25 | throw 'unresolved placeholder in learner artifact' |
출고표 25번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 26줄F06-L26 | } |
출고표 26번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 27줄F06-L27 | $NonBlank = |
출고표 27번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 조건을 만족하는 row만 필터링한다.
|
| 28줄F06-L28 | if ( |
출고표 28번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 조건·반복·함수의 실행 block을 연다.
|
| 29줄F06-L29 | throw "artifact needs at least three nonblank evidence lines: |
출고표 29번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 30줄F06-L30 | } |
출고표 30번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 31줄F06-L31 | $Hash = |
출고표 31번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 현재 bytes를 64자리 digest로 evidence에 결박한다.
|
| 32줄F06-L32 | "LOCAL_ARTIFACT_VALIDATED W24D3 bytes= |
출고표 32번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 파일 bytes·기본 형식·hash만 통과한 보조 marker를 낸다.
|
| 34줄F06-L34 | ## 경계 |
출고표 34번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다.
|
| 36줄F06-L36 | - LOCAL_ARTIFACT_VALIDATED는 bytes·placeholder·비공백 줄·hash만 확인한다. |
출고표 36번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 파일 bytes·기본 형식·hash만 통과한 보조 marker를 낸다.
|
| 37줄F06-L37 | - 원자성·잠금·멱등·대사·query·보안·운영의 위험-선택-test-결과-한계 연결은 사람이 읽는다. |
출고표 37번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W24-D3-readme-evidence.md의 다음 검증 또는 설명 단계를 구성한다.
|
| 38줄F06-L38 | - 실행하지 않은 환경 수치를 운영 보장으로 확대하지 않는다. |
출고표 38번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W24-D3-readme-evidence.md의 다음 검증 또는 설명 단계를 구성한다.
|
STEP 05 / 13
원본 코드 조각
원본을 4개 의미 조각으로 나누어 그대로 확인합니다.
파일을 한꺼번에 외우지 않고 실행 의미가 이어지는 작은 조각으로 봅니다. 아래 코드는 prompt·fixture·가정을 밝힌 학습용 예시 source이며, 제공 정본 답안이 아닙니다.
# W24 D3 README 학습 골격
> PDF p794–795의 TEMPLATE와 validator를 한 파일에 모은 학습용 예시다. 학습자 README 완성본이나 의미 Green이 아니다.
## Risk: concurrent reverse transfers
- Failure before: cyclic lock order produced SQLSTATE 40P01
- Choice: canonical sorted account lock order
- Verification: SortedLockTransferIT, 100 reverse runs
- Result: deadlock 0 within documented test envelope
- Limitation: local PostgreSQL 17.10, not production capacity
## 학습자 산출물 검사
$Artifact = Join-Path $LearnerRoot 'README.md'
if (!(Test-Path -LiteralPath $Artifact -PathType Leaf)) {
throw "learner artifact missing: $Artifact"
}
$Item = Get-Item -LiteralPath $Artifact
if ($Item.Length -lt 40) {
throw "artifact is too small to support the claim: bytes=$($Item.Length)"
}
$Text = Get-Content -LiteralPath $Artifact -Raw
if ($Text -match '(?i)\b(TODO|TBD|FILL_ME|PLACEHOLDER)\b') {
throw 'unresolved placeholder in learner artifact'
}
$NonBlank = @($Text -split '[\r\n]+' | Where-Object { $_.Trim().Length -gt 0 })
if ($NonBlank.Count -lt 3) {
throw "artifact needs at least three nonblank evidence lines: $($NonBlank.Count)"
}
$Hash = (Get-FileHash -LiteralPath $Artifact -Algorithm SHA256).Hash.ToLowerInvariant()
"LOCAL_ARTIFACT_VALIDATED W24D3 bytes=$($Item.Length) sha256=$Hash"
## 경계
- LOCAL_ARTIFACT_VALIDATED는 bytes·placeholder·비공백 줄·hash만 확인한다.
- 원자성·잠금·멱등·대사·query·보안·운영의 위험-선택-test-결과-한계 연결은 사람이 읽는다.
- 실행하지 않은 환경 수치를 운영 보장으로 확대하지 않는다.
STEP 06 / 13
코드 한 줄씩 한국어로 번역
비어 있지 않은 31줄을 모두 한국어로 옮깁니다.
비어 있지 않은 원본 줄은 하나도 생략하지 않습니다.
| 줄 | 원본 | 한국어 번역 |
|---|---|---|
| 1 | # W24 D3 README 학습 골격 | 문서 의미: 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다. |
| 3 | > PDF p794–795의 TEMPLATE와 validator를 한 파일에 모은 학습용 예시다. 학습자 README 완성본이나 의미 Green이 아니다. | 문서 의미: W24-D3-readme-evidence.md의 다음 검증 또는 설명 단계를 구성한다. |
| 5 | ## Risk: concurrent reverse transfers | 문서 의미: 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다. |
| 7 | - Failure before: cyclic lock order produced SQLSTATE 40P01 | 문서 의미: W24-D3-readme-evidence.md의 다음 검증 또는 설명 단계를 구성한다. |
| 8 | - Choice: canonical sorted account lock order | 문서 의미: W24-D3-readme-evidence.md의 다음 검증 또는 설명 단계를 구성한다. |
| 9 | - Verification: SortedLockTransferIT, 100 reverse runs | 문서 의미: W24-D3-readme-evidence.md의 다음 검증 또는 설명 단계를 구성한다. |
| 10 | - Result: deadlock 0 within documented test envelope | 문서 의미: W24-D3-readme-evidence.md의 다음 검증 또는 설명 단계를 구성한다. |
| 11 | - Limitation: local PostgreSQL 17.10, not production capacity | 문서 의미: W24-D3-readme-evidence.md의 다음 검증 또는 설명 단계를 구성한다. |
| 13 | ## 학습자 산출물 검사 | 문서 의미: 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다. |
| 15 | $Artifact = Join-Path $LearnerRoot 'README.md' | 문서 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 16 | if (!(Test-Path -LiteralPath $Artifact -PathType Leaf)) { | 문서 의미: 필수 파일이나 경로가 실제로 있는지 확인한다. |
| 17 | throw "learner artifact missing: $Artifact" | 문서 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 18 | } | 문서 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 19 | $Item = Get-Item -LiteralPath $Artifact | 문서 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 20 | if ($Item.Length -lt 40) { | 문서 의미: 조건·반복·함수의 실행 block을 연다. |
| 21 | throw "artifact is too small to support the claim: bytes=$($Item.Length)" | 문서 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 22 | } | 문서 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 23 | $Text = Get-Content -LiteralPath $Artifact -Raw | 문서 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 24 | if ($Text -match '(?i)\b(TODO|TBD|FILL_ME|PLACEHOLDER)\b') { | 문서 의미: Markdown 표 또는 PowerShell pipeline에서 값을 열이나 다음 명령으로 연결한다. |
| 25 | throw 'unresolved placeholder in learner artifact' | 문서 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 26 | } | 문서 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 27 | $NonBlank = @($Text -split '[\r\n]+' | Where-Object { $_.Trim().Length -gt 0 }) | 문서 의미: 조건을 만족하는 row만 필터링한다. |
| 28 | if ($NonBlank.Count -lt 3) { | 문서 의미: 조건·반복·함수의 실행 block을 연다. |
| 29 | throw "artifact needs at least three nonblank evidence lines: $($NonBlank.Count)" | 문서 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 30 | } | 문서 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 31 | $Hash = (Get-FileHash -LiteralPath $Artifact -Algorithm SHA256).Hash.ToLowerInvariant() | 문서 의미: 현재 bytes를 64자리 digest로 evidence에 결박한다. |
| 32 | "LOCAL_ARTIFACT_VALIDATED W24D3 bytes=$($Item.Length) sha256=$Hash" | 문서 의미: 파일 bytes·기본 형식·hash만 통과한 보조 marker를 낸다. |
| 34 | ## 경계 | 문서 의미: 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다. |
| 36 | - LOCAL_ARTIFACT_VALIDATED는 bytes·placeholder·비공백 줄·hash만 확인한다. | 문서 의미: 파일 bytes·기본 형식·hash만 통과한 보조 marker를 낸다. |
| 37 | - 원자성·잠금·멱등·대사·query·보안·운영의 위험-선택-test-결과-한계 연결은 사람이 읽는다. | 문서 의미: W24-D3-readme-evidence.md의 다음 검증 또는 설명 단계를 구성한다. |
| 38 | - 실행하지 않은 환경 수치를 운영 보장으로 확대하지 않는다. | 문서 의미: W24-D3-readme-evidence.md의 다음 검증 또는 설명 단계를 구성한다. |
STEP 07 / 13
기존 수준의 한 줄 읽기·문법 해부
쉬운 설명 다음에 문법과 실행 순서를 정밀하게 읽습니다.
한 줄로 읽기W24 D3 README — 위험·선택·검증·결과·한계 연결는 기능 나열 대신 일곱 위험을 evidence path와 test envelope에 연결하는 README 골격과 형식 validator를 보여 준다.
문법 해부
- .md 문법에서 선언·조건·pipeline·block 경계를 먼저 나눈다.
- expected 값과 actual 결과를 같은 이름처럼 보여도 서로 다른 source로 읽는다.
- native exit·row count·hash·사람 판정을 서로 대체하지 않는다.
실행 순서
- 입력 경로·fixture·환경변수·expected 계약을 고정한다.
- source가 실행하는 native process·HTTP·SQL 또는 형식 검사를 따라간다.
- actual 값과 exact marker를 대조하고 실패면 성공 발행 전에 중단한다.
- finally cleanup과 비범위를 evidence에 남긴다.
W24 조각별 정밀 해설
F06-C01 · 원문 1–12줄
- 문법 해부
- .md 문법으로 1–12줄의 선언·조건·pipeline·block을 나눈다.
- 실제 값 추적
- SQLSTATE 40P01, SortedLockTransferIT, 100 reverse runs를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- expected와 actual이 일치하고 owner evidence가 같은 run/hash에 연결되는 경우다.
- 틀린 예·반례
- 학습자 README 완성본이 아니다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- 파일 존재·문자열·hash·exit0 하나를 의미 Green 전체와 같다고 보지 않는다.
- 하지 않는 일
- 학습자 README 완성본이 아니다; hash는 내용의 진실성을 증명하지 않는다; 운영 용량 보장이 아니다
- 다음 연결
- 다음 조각 또는 F06 evidence 판정으로 상태를 넘긴다.
F06-C02 · 원문 13–24줄
- 문법 해부
- .md 문법으로 13–24줄의 선언·조건·pipeline·block을 나눈다.
- 실제 값 추적
- SQLSTATE 40P01, SortedLockTransferIT, 100 reverse runs를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- expected와 actual이 일치하고 owner evidence가 같은 run/hash에 연결되는 경우다.
- 틀린 예·반례
- 학습자 README 완성본이 아니다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- 파일 존재·문자열·hash·exit0 하나를 의미 Green 전체와 같다고 보지 않는다.
- 하지 않는 일
- 학습자 README 완성본이 아니다; hash는 내용의 진실성을 증명하지 않는다; 운영 용량 보장이 아니다
- 다음 연결
- 다음 조각 또는 F06 evidence 판정으로 상태를 넘긴다.
F06-C03 · 원문 25–36줄
- 문법 해부
- .md 문법으로 25–36줄의 선언·조건·pipeline·block을 나눈다.
- 실제 값 추적
- SQLSTATE 40P01, SortedLockTransferIT, 100 reverse runs를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- expected와 actual이 일치하고 owner evidence가 같은 run/hash에 연결되는 경우다.
- 틀린 예·반례
- 학습자 README 완성본이 아니다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- 파일 존재·문자열·hash·exit0 하나를 의미 Green 전체와 같다고 보지 않는다.
- 하지 않는 일
- 학습자 README 완성본이 아니다; hash는 내용의 진실성을 증명하지 않는다; 운영 용량 보장이 아니다
- 다음 연결
- 다음 조각 또는 F06 evidence 판정으로 상태를 넘긴다.
F06-C04 · 원문 37–38줄
- 문법 해부
- .md 문법으로 37–38줄의 선언·조건·pipeline·block을 나눈다.
- 실제 값 추적
- SQLSTATE 40P01, SortedLockTransferIT, 100 reverse runs를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- expected와 actual이 일치하고 owner evidence가 같은 run/hash에 연결되는 경우다.
- 틀린 예·반례
- 학습자 README 완성본이 아니다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- 파일 존재·문자열·hash·exit0 하나를 의미 Green 전체와 같다고 보지 않는다.
- 하지 않는 일
- 학습자 README 완성본이 아니다; hash는 내용의 진실성을 증명하지 않는다; 운영 용량 보장이 아니다
- 다음 연결
- 다음 조각 또는 F06 evidence 판정으로 상태를 넘긴다.
실행 순서 — W24 D3 README — 위험·선택·검증·결과·한계 연결
-
SortedLockTransferIT가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 기능 나열 대신 일곱 위험을 evidence path와 test envelope에 연결하는 README 골격과 형식 validator를 보여 준다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘hash는 내용의 진실성을 증명하지 않는다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 SortedLockTransferIT와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 08 / 13
실제 값 따라가기
같은 입력값이 어느 줄을 지나 어떤 결과가 되는지 추적합니다.
| 순서 | 들어온 값 | 코드가 하는 일 | 나온 값·상태 | 경계 |
|---|---|---|---|---|
| 입력 | SQLSTATE 40P01 | source 계약에 대입 | F06 실행/설명 시작 상태 | 학습자 README 완성본이 아니다 |
| 검증 | SortedLockTransferIT | expected와 actual 또는 형식 대조 | 통과 또는 첫 mismatch | hash는 내용의 진실성을 증명하지 않는다 |
| 증거 | LOCAL_ARTIFACT_VALIDATED | marker·hash·row를 같은 run에 연결 | 범위가 적힌 evidence 후보 | 운영 용량 보장이 아니다 |
실제 값 — W24 D3 README — 위험·선택·검증·결과·한계 연결
-
100 reverse runs가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 기능 나열 대신 일곱 위험을 evidence path와 test envelope에 연결하는 README 골격과 형식 validator를 보여 준다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘운영 용량 보장이 아니다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 100 reverse runs와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 09 / 13
Gradle·PowerShell·HTTP·PostgreSQL 내부에서 벌어지는 일
Gradle·JUnit XML·PowerShell·HTTP·PostgreSQL·Docker에서 실제로 일어나는 일과 증명 범위를 구분합니다.
W24-D3-readme-evidence.md bytes와 expected 값을 읽는다.
파일 존재만으로 runtime 성공은 아니다.native exit·HTTP status·JUnit XML·DB row·hash 중 이 파일이 소유한 값을 만든다.
학습자 README 완성본이 아니다관련 evidence와 사람 의미 검토를 release 후보에 연결한다.
운영 용량 보장이 아니다첫 실패 경계 — W24 D3 README — 위험·선택·검증·결과·한계 연결
-
LOCAL_ARTIFACT_VALIDATED가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 기능 나열 대신 일곱 위험을 evidence path와 test envelope에 연결하는 README 골격과 형식 validator를 보여 준다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘학습자 README 완성본이 아니다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 LOCAL_ARTIFACT_VALIDATED와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 10 / 13
흔한 착각과 틀린 예
그럴듯하지만 틀린 해석을 반례로 고칩니다.
❌ SQLSTATE 40P01 문자열이 source에 있으니 실제 실행도 Green이다.
왜 틀리나 source literal과 runtime 관찰값은 다른 증거다.
바르게 읽기 native exit·actual XML/HTTP/DB evidence를 별도로 확인한다.
반례 script가 실행 전 경로 오류로 멈춰도 literal은 그대로 남는다.
❌ 파일 SHA-256이 있으면 내용의 의미와 사실성도 검증됐다.
왜 틀리나 hash는 동일 bytes만 말한다.
바르게 읽기 schema·수치·질문·근거는 별도 자동 또는 사람 판정을 거친다.
반례 빈 review 질문을 가진 CSV도 안정된 hash를 가진다.
❌ LOCAL_ARTIFACT_VALIDATED는 release Green과 같다.
왜 틀리나 generic validator는 파일 shape만 확인한다.
바르게 읽기 HUMAN_SEMANTIC_REVIEW_REQUIRED를 유지한다.
반례 잘못된 track 점수표도 byte 수 조건은 통과할 수 있다.
❌ 이 파일이 W24 전체 lifecycle을 모두 소유한다.
왜 틀리나 각 source는 Gate·demo·cleanup·사람 review 중 일부만 담당한다.
바르게 읽기 owner와 non-responsibility를 release manifest에서 분리한다.
반례 D4 source audit에는 runtime_claim=false가 명시된다.
❌ 이전 주 Green이나 오래된 log를 현재 commit 결과로 재사용한다.
왜 틀리나 source·commit·actual result가 같은 실행에 묶이지 않는다.
바르게 읽기 release 후보에서 새 evidence와 hash를 만든다.
반례 expected JSON이 바뀌면 예전 XML은 exact inventory를 증명하지 못한다.
STEP 11 / 13
이 코드가 보장하지 않는 것
이 코드가 책임지지 않는 일을 분리합니다.
학습자 README 완성본이 아니다
이 책임을 맡는 곳: runtime Gatehash는 내용의 진실성을 증명하지 않는다
이 책임을 맡는 곳: external/human review운영 용량 보장이 아니다
이 책임을 맡는 곳: release manifest학습자 README 완성본이 아니다
이 책임을 맡는 곳: 운영 환경증명하지 않는 범위 — W24 D3 README — 위험·선택·검증·결과·한계 연결
-
SQLSTATE 40P01가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 기능 나열 대신 일곱 위험을 evidence path와 test envelope에 연결하는 README 골격과 형식 validator를 보여 준다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘hash는 내용의 진실성을 증명하지 않는다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 SQLSTATE 40P01와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 12 / 13
직접 다시 써보기
뜻 → 조각 → 전체 코드 순서로 다시 씁니다.
1단계 · 뜻부터 복원
- 기능 나열 대신 일곱 위험을 evidence path와 test envelope에 연결하는 README 골격과 형식 validator를 보여 준다.
- 핵심 값은 SQLSTATE 40P01, SortedLockTransferIT, 100 reverse runs, LOCAL_ARTIFACT_VALIDATED다.
2단계 · 코드 조각 재조립
- 1. 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다
- 3. W24-D3-readme-evidence.md의 다음 검증 또는 설명 단계를 구성한다
- 5. 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다
- 7. W24-D3-readme-evidence.md의 다음 검증 또는 설명 단계를 구성한다
- 8. W24-D3-readme-evidence.md의 다음 검증 또는 설명 단계를 구성한다
- 9. W24-D3-readme-evidence.md의 다음 검증 또는 설명 단계를 구성한다
- 10. W24-D3-readme-evidence.md의 다음 검증 또는 설명 단계를 구성한다
- 11. W24-D3-readme-evidence.md의 다음 검증 또는 설명 단계를 구성한다
3단계 · 파일 전체 다시 쓰기
illustrative/markdown/W24-D3-readme-evidence.md을 새 파일에 다시 쓰고 expected·actual·실패·cleanup·비범위를 주석으로 표시한다.
자가 점검
- 비어 있지 않은 모든 source 줄을 한 번씩 읽었나?
- source shape와 runtime Green을 분리했나?
- 사람 검토·외부 상태를 자동 성공으로 꾸미지 않았나?
- 첫 실패와 cleanup 책임을 설명할 수 있나?
STEP 13 / 13
전체 원본 source
감사로 고정한 전체 source를 가감 없이 확인합니다.
학습용 예시 전체 확인하기 · 정본 답안 아님
# W24 D3 README 학습 골격
> PDF p794–795의 TEMPLATE와 validator를 한 파일에 모은 학습용 예시다. 학습자 README 완성본이나 의미 Green이 아니다.
## Risk: concurrent reverse transfers
- Failure before: cyclic lock order produced SQLSTATE 40P01
- Choice: canonical sorted account lock order
- Verification: SortedLockTransferIT, 100 reverse runs
- Result: deadlock 0 within documented test envelope
- Limitation: local PostgreSQL 17.10, not production capacity
## 학습자 산출물 검사
$Artifact = Join-Path $LearnerRoot 'README.md'
if (!(Test-Path -LiteralPath $Artifact -PathType Leaf)) {
throw "learner artifact missing: $Artifact"
}
$Item = Get-Item -LiteralPath $Artifact
if ($Item.Length -lt 40) {
throw "artifact is too small to support the claim: bytes=$($Item.Length)"
}
$Text = Get-Content -LiteralPath $Artifact -Raw
if ($Text -match '(?i)\b(TODO|TBD|FILL_ME|PLACEHOLDER)\b') {
throw 'unresolved placeholder in learner artifact'
}
$NonBlank = @($Text -split '[\r\n]+' | Where-Object { $_.Trim().Length -gt 0 })
if ($NonBlank.Count -lt 3) {
throw "artifact needs at least three nonblank evidence lines: $($NonBlank.Count)"
}
$Hash = (Get-FileHash -LiteralPath $Artifact -Algorithm SHA256).Hash.ToLowerInvariant()
"LOCAL_ARTIFACT_VALIDATED W24D3 bytes=$($Item.Length) sha256=$Hash"
## 경계
- LOCAL_ARTIFACT_VALIDATED는 bytes·placeholder·비공백 줄·hash만 확인한다.
- 원자성·잠금·멱등·대사·query·보안·운영의 위험-선택-test-결과-한계 연결은 사람이 읽는다.
- 실행하지 않은 환경 수치를 운영 보장으로 확대하지 않는다.
07W24-SQL-Q39 — 전월에는 있고 당월에는 없는 고객
illustrative/sql/W24-SQL-Q39.sql
학습용 예시 · Q39/Q40 prompt 기반 SQL · 정본 답안 아님 · workbook 제공 정답 아님 · 학습용 예시 · 정본 답안 아님 · W24-F0739줄 연결39줄 번역4 chunks
W24-SQL-Q39 — 전월에는 있고 당월에는 없는 고객
illustrative/sql/W24-SQL-Q39.sql
학습용 예시 · Q39/Q40 prompt 기반 SQL · 정본 답안 아님 · workbook 제공 정답 아님 · 학습용 예시 · 정본 답안 아님 · W24-F07STEP 01 / 13
오늘 이 코드에서 해결할 문제
무엇을 이해해야 하는지 질문부터 잡습니다.
fixture_clock 기준 반개구간과 NOT EXISTS를 사용해 전월 SUCCESS 고객 집합에서 당월 활동 고객을 NULL-safe하게 제외한다.
- previous month은 어느 source와 실제 결과에서 확인해야 할까?
- 첫 실패를 만드는 조건과 fail-closed 지점은 어디일까?
- 왜 ‘workbook 제공 정답이 아니다’를 별도 경계로 남겨야 할까?
previous monthcurrent monthNOT EXISTShalf-open rangeSUCCESS왜 필요한가 — W24-SQL-Q39 — 전월에는 있고 당월에는 없는 고객
-
previous month가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 fixture_clock 기준 반개구간과 NOT EXISTS를 사용해 전월 SUCCESS 고객 집합에서 당월 활동 고객을 NULL-safe하게 제외한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘workbook 제공 정답이 아니다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 previous month와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 02 / 13
아주 짧게: 이 코드는 왜 필요할까?
웹소설 대신 이 코드가 필요한 이유만 두 문단으로 쉽게 봅니다.
새 기능을 멈춘 팀이 코드·test·문서·demo를 같은 release 후보에 묶어 하나씩 검수한다.
검수 도장이 붙은 공통 거래 코어 출고 상자
이 파일은 fixture_clock 기준 반개구간과 NOT EXISTS를 사용해 전월 SUCCESS 고객 집합에서 당월 활동 고객을 NULL-safe하게 제외한다. 눈으로 읽을 때는 각 줄을 검수표 한 칸처럼 보고, 입력과 다음 상태를 놓치지 않는다.
마지막 도장은 source shape와 실제 runtime·사람 검토를 구분한 뒤에만 찍는다. 특히 workbook 제공 정답이 아니다
딱 여기까지만 비유는 실행 순서를 돕지만 실제 Gradle·Docker·DB·사람 review를 대신하지 않는다.
STEP 03 / 13
초등학생도 이해하는 설명
생활 비유와 실제 코드의 경계를 함께 확인합니다.
값 1: previous month
이 파일에서 계속 확인할 고정 단서가 previous month다.
- 코드 연결
F07 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- workbook 제공 정답이 아니다
값 2: current month
이 파일에서 계속 확인할 고정 단서가 current month다.
- 코드 연결
F07 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- SUCCESS만 활동으로 센다는 가정을 명시한다
값 3: NOT EXISTS
이 파일에서 계속 확인할 고정 단서가 NOT EXISTS다.
- 코드 연결
F07 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- 실제 PostgreSQL 실행 결과가 아니다
값 4: half-open range
이 파일에서 계속 확인할 고정 단서가 half-open range다.
- 코드 연결
F07 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- workbook 제공 정답이 아니다
값 5: SUCCESS
이 파일에서 계속 확인할 고정 단서가 SUCCESS다.
- 코드 연결
F07 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- SUCCESS만 활동으로 센다는 가정을 명시한다
STEP 04 / 13
비유 ↔ 코드 전체 연결표
감사 규칙상 연결 대상인 원본 39줄을 빠짐없이 연결합니다.
| 줄 | 정확한 원본 줄 | STARRY 비유 | 실제 뜻·입력·결과·한계 |
|---|---|---|---|
| 1줄F07-L01 | -- W24-SQL-Q39 학습용 예시이며 workbook 제공 정답이 아니다. |
출고표 1번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W24-SQL-Q39.sql의 다음 검증 또는 설명 단계를 구성한다.
|
| 2줄F07-L02 | -- 가정: |
출고표 2번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W24-SQL-Q39.sql의 다음 검증 또는 설명 단계를 구성한다.
|
| 3줄F07-L03 | -- 입력 grain: |
출고표 3번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W24-SQL-Q39.sql의 다음 검증 또는 설명 단계를 구성한다.
|
| 4줄F07-L04 | WITH bounds AS ( |
출고표 4번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 SQL 집합의 입력·변환·필터 단계를 선언한다.
|
| 5줄F07-L05 | SELECT |
출고표 5번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 SQL 집합의 입력·변환·필터 단계를 선언한다.
|
| 6줄F07-L06 | date_trunc( |
출고표 6번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 fixture clock을 달 시작 경계로 정규화한다.
|
| 7줄F07-L07 | date_trunc( |
출고표 7번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 fixture clock을 달 시작 경계로 정규화한다.
|
| 8줄F07-L08 | FROM fixture_clock |
출고표 8번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 SQL 집합의 입력·변환·필터 단계를 선언한다.
|
| 9줄F07-L09 | ), |
출고표 9번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W24-SQL-Q39.sql의 다음 검증 또는 설명 단계를 구성한다.
|
| 10줄F07-L10 | previous_customers AS ( |
출고표 10번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W24-SQL-Q39.sql의 다음 검증 또는 설명 단계를 구성한다.
|
| 11줄F07-L11 | SELECT DISTINCT a. |
출고표 11번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 SQL 집합의 입력·변환·필터 단계를 선언한다.
|
| 12줄F07-L12 | FROM business_tx AS tx |
출고표 12번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 SQL 집합의 입력·변환·필터 단계를 선언한다.
|
| 13줄F07-L13 | JOIN account AS a |
출고표 13번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 SQL 집합의 입력·변환·필터 단계를 선언한다.
|
| 14줄F07-L14 | ON a. |
출고표 14번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W24-SQL-Q39.sql의 다음 검증 또는 설명 단계를 구성한다.
|
| 15줄F07-L15 | CROSS JOIN bounds AS b |
출고표 15번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W24-SQL-Q39.sql의 다음 검증 또는 설명 단계를 구성한다.
|
| 16줄F07-L16 | WHERE tx. |
출고표 16번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 SQL 집합의 입력·변환·필터 단계를 선언한다.
|
| 17줄F07-L17 | AND tx. |
출고표 17번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W24-SQL-Q39.sql의 다음 검증 또는 설명 단계를 구성한다.
|
| 18줄F07-L18 | AND tx. |
출고표 18번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W24-SQL-Q39.sql의 다음 검증 또는 설명 단계를 구성한다.
|
| 19줄F07-L19 | ) |
출고표 19번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 20줄F07-L20 | SELECT |
출고표 20번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 SQL 집합의 입력·변환·필터 단계를 선언한다.
|
| 21줄F07-L21 | c. |
출고표 21번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W24-SQL-Q39.sql의 다음 검증 또는 설명 단계를 구성한다.
|
| 22줄F07-L22 | c. |
출고표 22번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W24-SQL-Q39.sql의 다음 검증 또는 설명 단계를 구성한다.
|
| 23줄F07-L23 | FROM previous_customers AS p |
출고표 23번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 SQL 집합의 입력·변환·필터 단계를 선언한다.
|
| 24줄F07-L24 | JOIN customer AS c |
출고표 24번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 SQL 집합의 입력·변환·필터 단계를 선언한다.
|
| 25줄F07-L25 | ON c. |
출고표 25번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W24-SQL-Q39.sql의 다음 검증 또는 설명 단계를 구성한다.
|
| 26줄F07-L26 | WHERE NOT EXISTS ( |
출고표 26번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 당월에 대응 거래가 하나라도 있으면 그 고객을 결과에서 제외한다.
|
| 27줄F07-L27 | SELECT 1 |
출고표 27번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 SQL 집합의 입력·변환·필터 단계를 선언한다.
|
| 28줄F07-L28 | FROM account AS a |
출고표 28번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 SQL 집합의 입력·변환·필터 단계를 선언한다.
|
| 29줄F07-L29 | JOIN business_tx AS tx |
출고표 29번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 SQL 집합의 입력·변환·필터 단계를 선언한다.
|
| 30줄F07-L30 | ON tx. |
출고표 30번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W24-SQL-Q39.sql의 다음 검증 또는 설명 단계를 구성한다.
|
| 31줄F07-L31 | CROSS JOIN bounds AS b |
출고표 31번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W24-SQL-Q39.sql의 다음 검증 또는 설명 단계를 구성한다.
|
| 32줄F07-L32 | WHERE a. |
출고표 32번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 SQL 집합의 입력·변환·필터 단계를 선언한다.
|
| 33줄F07-L33 | AND tx. |
출고표 33번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W24-SQL-Q39.sql의 다음 검증 또는 설명 단계를 구성한다.
|
| 34줄F07-L34 | AND tx. |
출고표 34번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W24-SQL-Q39.sql의 다음 검증 또는 설명 단계를 구성한다.
|
| 35줄F07-L35 | AND tx. |
출고표 35번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 반개구간의 이전 달 또는 다음 달 경계를 계산한다.
|
| 36줄F07-L36 | ) |
출고표 36번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 37줄F07-L37 | ORDER BY c. |
출고표 37번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 출력 또는 window 계산 순서를 안정적으로 정한다.
|
| 39줄F07-L39 | -- NULL-safe 반례: |
출고표 39번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 당월에 대응 거래가 하나라도 있으면 그 고객을 결과에서 제외한다.
|
| 40줄F07-L40 | -- 경계 반례: |
출고표 40번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W24-SQL-Q39.sql의 다음 검증 또는 설명 단계를 구성한다.
|
STEP 05 / 13
원본 코드 조각
원본을 4개 의미 조각으로 나누어 그대로 확인합니다.
파일을 한꺼번에 외우지 않고 실행 의미가 이어지는 작은 조각으로 봅니다. 아래 코드는 prompt·fixture·가정을 밝힌 학습용 예시 source이며, 제공 정본 답안이 아닙니다.
-- W24-SQL-Q39 학습용 예시이며 workbook 제공 정답이 아니다.
-- 가정: 전월/당월은 fixture_clock.as_of가 속한 달을 기준으로 하고 SUCCESS 거래만 활동으로 센다.
-- 입력 grain: business_tx 한 행 = 거래 한 건. 출력 grain: customer 한 행. 예상 cardinality는 fixture 실행으로 확인한다.
WITH bounds AS (
SELECT
date_trunc('month', as_of) AS current_start,
date_trunc('month', as_of) - INTERVAL '1 month' AS previous_start
FROM fixture_clock
),
previous_customers AS (
SELECT DISTINCT a.customer_id
FROM business_tx AS tx
JOIN account AS a
ON a.account_id = tx.account_id
CROSS JOIN bounds AS b
WHERE tx.status = 'SUCCESS'
AND tx.occurred_at >= b.previous_start
AND tx.occurred_at < b.current_start
)
SELECT
c.customer_id,
c.customer_name
FROM previous_customers AS p
JOIN customer AS c
ON c.customer_id = p.customer_id
WHERE NOT EXISTS (
SELECT 1
FROM account AS a
JOIN business_tx AS tx
ON tx.account_id = a.account_id
CROSS JOIN bounds AS b
WHERE a.customer_id = p.customer_id
AND tx.status = 'SUCCESS'
AND tx.occurred_at >= b.current_start
AND tx.occurred_at < b.current_start + INTERVAL '1 month'
)
ORDER BY c.customer_id;
-- NULL-safe 반례: NOT EXISTS는 subquery에 NULL 값이 있어도 NOT IN처럼 전체 결과가 UNKNOWN으로 오염되지 않는다.
-- 경계 반례: current_start 시각의 거래는 전월이 아니라 당월에 정확히 한 번 포함된다.
STEP 06 / 13
코드 한 줄씩 한국어로 번역
비어 있지 않은 39줄을 모두 한국어로 옮깁니다.
비어 있지 않은 원본 줄은 하나도 생략하지 않습니다.
| 줄 | 원본 | 한국어 번역 |
|---|---|---|
| 1 | -- W24-SQL-Q39 학습용 예시이며 workbook 제공 정답이 아니다. | 실행 의미: W24-SQL-Q39.sql의 다음 검증 또는 설명 단계를 구성한다. |
| 2 | -- 가정: 전월/당월은 fixture_clock.as_of가 속한 달을 기준으로 하고 SUCCESS 거래만 활동으로 센다. | 실행 의미: W24-SQL-Q39.sql의 다음 검증 또는 설명 단계를 구성한다. |
| 3 | -- 입력 grain: business_tx 한 행 = 거래 한 건. 출력 grain: customer 한 행. 예상 cardinality는 fixture 실행으로 확인한다. | 실행 의미: W24-SQL-Q39.sql의 다음 검증 또는 설명 단계를 구성한다. |
| 4 | WITH bounds AS ( | 실행 의미: SQL 집합의 입력·변환·필터 단계를 선언한다. |
| 5 | SELECT | 실행 의미: SQL 집합의 입력·변환·필터 단계를 선언한다. |
| 6 | date_trunc('month', as_of) AS current_start, | 실행 의미: fixture clock을 달 시작 경계로 정규화한다. |
| 7 | date_trunc('month', as_of) - INTERVAL '1 month' AS previous_start | 실행 의미: fixture clock을 달 시작 경계로 정규화한다. |
| 8 | FROM fixture_clock | 실행 의미: SQL 집합의 입력·변환·필터 단계를 선언한다. |
| 9 | ), | 실행 의미: W24-SQL-Q39.sql의 다음 검증 또는 설명 단계를 구성한다. |
| 10 | previous_customers AS ( | 실행 의미: W24-SQL-Q39.sql의 다음 검증 또는 설명 단계를 구성한다. |
| 11 | SELECT DISTINCT a.customer_id | 실행 의미: SQL 집합의 입력·변환·필터 단계를 선언한다. |
| 12 | FROM business_tx AS tx | 실행 의미: SQL 집합의 입력·변환·필터 단계를 선언한다. |
| 13 | JOIN account AS a | 실행 의미: SQL 집합의 입력·변환·필터 단계를 선언한다. |
| 14 | ON a.account_id = tx.account_id | 실행 의미: W24-SQL-Q39.sql의 다음 검증 또는 설명 단계를 구성한다. |
| 15 | CROSS JOIN bounds AS b | 실행 의미: W24-SQL-Q39.sql의 다음 검증 또는 설명 단계를 구성한다. |
| 16 | WHERE tx.status = 'SUCCESS' | 실행 의미: SQL 집합의 입력·변환·필터 단계를 선언한다. |
| 17 | AND tx.occurred_at >= b.previous_start | 실행 의미: W24-SQL-Q39.sql의 다음 검증 또는 설명 단계를 구성한다. |
| 18 | AND tx.occurred_at < b.current_start | 실행 의미: W24-SQL-Q39.sql의 다음 검증 또는 설명 단계를 구성한다. |
| 19 | ) | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 20 | SELECT | 실행 의미: SQL 집합의 입력·변환·필터 단계를 선언한다. |
| 21 | c.customer_id, | 실행 의미: W24-SQL-Q39.sql의 다음 검증 또는 설명 단계를 구성한다. |
| 22 | c.customer_name | 실행 의미: W24-SQL-Q39.sql의 다음 검증 또는 설명 단계를 구성한다. |
| 23 | FROM previous_customers AS p | 실행 의미: SQL 집합의 입력·변환·필터 단계를 선언한다. |
| 24 | JOIN customer AS c | 실행 의미: SQL 집합의 입력·변환·필터 단계를 선언한다. |
| 25 | ON c.customer_id = p.customer_id | 실행 의미: W24-SQL-Q39.sql의 다음 검증 또는 설명 단계를 구성한다. |
| 26 | WHERE NOT EXISTS ( | 실행 의미: 당월에 대응 거래가 하나라도 있으면 그 고객을 결과에서 제외한다. |
| 27 | SELECT 1 | 실행 의미: SQL 집합의 입력·변환·필터 단계를 선언한다. |
| 28 | FROM account AS a | 실행 의미: SQL 집합의 입력·변환·필터 단계를 선언한다. |
| 29 | JOIN business_tx AS tx | 실행 의미: SQL 집합의 입력·변환·필터 단계를 선언한다. |
| 30 | ON tx.account_id = a.account_id | 실행 의미: W24-SQL-Q39.sql의 다음 검증 또는 설명 단계를 구성한다. |
| 31 | CROSS JOIN bounds AS b | 실행 의미: W24-SQL-Q39.sql의 다음 검증 또는 설명 단계를 구성한다. |
| 32 | WHERE a.customer_id = p.customer_id | 실행 의미: SQL 집합의 입력·변환·필터 단계를 선언한다. |
| 33 | AND tx.status = 'SUCCESS' | 실행 의미: W24-SQL-Q39.sql의 다음 검증 또는 설명 단계를 구성한다. |
| 34 | AND tx.occurred_at >= b.current_start | 실행 의미: W24-SQL-Q39.sql의 다음 검증 또는 설명 단계를 구성한다. |
| 35 | AND tx.occurred_at < b.current_start + INTERVAL '1 month' | 실행 의미: 반개구간의 이전 달 또는 다음 달 경계를 계산한다. |
| 36 | ) | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 37 | ORDER BY c.customer_id; | 실행 의미: 출력 또는 window 계산 순서를 안정적으로 정한다. |
| 39 | -- NULL-safe 반례: NOT EXISTS는 subquery에 NULL 값이 있어도 NOT IN처럼 전체 결과가 UNKNOWN으로 오염되지 않는다. | 실행 의미: 당월에 대응 거래가 하나라도 있으면 그 고객을 결과에서 제외한다. |
| 40 | -- 경계 반례: current_start 시각의 거래는 전월이 아니라 당월에 정확히 한 번 포함된다. | 실행 의미: W24-SQL-Q39.sql의 다음 검증 또는 설명 단계를 구성한다. |
STEP 07 / 13
기존 수준의 한 줄 읽기·문법 해부
쉬운 설명 다음에 문법과 실행 순서를 정밀하게 읽습니다.
한 줄로 읽기W24-SQL-Q39 — 전월에는 있고 당월에는 없는 고객는 fixture_clock 기준 반개구간과 NOT EXISTS를 사용해 전월 SUCCESS 고객 집합에서 당월 활동 고객을 NULL-safe하게 제외한다.
문법 해부
- .sql 문법에서 선언·조건·pipeline·block 경계를 먼저 나눈다.
- expected 값과 actual 결과를 같은 이름처럼 보여도 서로 다른 source로 읽는다.
- native exit·row count·hash·사람 판정을 서로 대체하지 않는다.
실행 순서
- 입력 경로·fixture·환경변수·expected 계약을 고정한다.
- source가 실행하는 native process·HTTP·SQL 또는 형식 검사를 따라간다.
- actual 값과 exact marker를 대조하고 실패면 성공 발행 전에 중단한다.
- finally cleanup과 비범위를 evidence에 남긴다.
W24 조각별 정밀 해설
F07-C01 · 원문 1–12줄
- 문법 해부
- .sql 문법으로 1–12줄의 선언·조건·pipeline·block을 나눈다.
- 실제 값 추적
- previous month, current month, NOT EXISTS를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- expected와 actual이 일치하고 owner evidence가 같은 run/hash에 연결되는 경우다.
- 틀린 예·반례
- workbook 제공 정답이 아니다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- 파일 존재·문자열·hash·exit0 하나를 의미 Green 전체와 같다고 보지 않는다.
- 하지 않는 일
- workbook 제공 정답이 아니다; SUCCESS만 활동으로 센다는 가정을 명시한다; 실제 PostgreSQL 실행 결과가 아니다
- 다음 연결
- 다음 조각 또는 F07 evidence 판정으로 상태를 넘긴다.
F07-C02 · 원문 13–24줄
- 문법 해부
- .sql 문법으로 13–24줄의 선언·조건·pipeline·block을 나눈다.
- 실제 값 추적
- previous month, current month, NOT EXISTS를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- expected와 actual이 일치하고 owner evidence가 같은 run/hash에 연결되는 경우다.
- 틀린 예·반례
- workbook 제공 정답이 아니다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- 파일 존재·문자열·hash·exit0 하나를 의미 Green 전체와 같다고 보지 않는다.
- 하지 않는 일
- workbook 제공 정답이 아니다; SUCCESS만 활동으로 센다는 가정을 명시한다; 실제 PostgreSQL 실행 결과가 아니다
- 다음 연결
- 다음 조각 또는 F07 evidence 판정으로 상태를 넘긴다.
F07-C03 · 원문 25–36줄
- 문법 해부
- .sql 문법으로 25–36줄의 선언·조건·pipeline·block을 나눈다.
- 실제 값 추적
- previous month, current month, NOT EXISTS를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- expected와 actual이 일치하고 owner evidence가 같은 run/hash에 연결되는 경우다.
- 틀린 예·반례
- workbook 제공 정답이 아니다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- 파일 존재·문자열·hash·exit0 하나를 의미 Green 전체와 같다고 보지 않는다.
- 하지 않는 일
- workbook 제공 정답이 아니다; SUCCESS만 활동으로 센다는 가정을 명시한다; 실제 PostgreSQL 실행 결과가 아니다
- 다음 연결
- 다음 조각 또는 F07 evidence 판정으로 상태를 넘긴다.
F07-C04 · 원문 37–40줄
- 문법 해부
- .sql 문법으로 37–40줄의 선언·조건·pipeline·block을 나눈다.
- 실제 값 추적
- previous month, current month, NOT EXISTS를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- expected와 actual이 일치하고 owner evidence가 같은 run/hash에 연결되는 경우다.
- 틀린 예·반례
- workbook 제공 정답이 아니다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- 파일 존재·문자열·hash·exit0 하나를 의미 Green 전체와 같다고 보지 않는다.
- 하지 않는 일
- workbook 제공 정답이 아니다; SUCCESS만 활동으로 센다는 가정을 명시한다; 실제 PostgreSQL 실행 결과가 아니다
- 다음 연결
- 다음 조각 또는 F07 evidence 판정으로 상태를 넘긴다.
실행 순서 — W24-SQL-Q39 — 전월에는 있고 당월에는 없는 고객
-
current month가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 fixture_clock 기준 반개구간과 NOT EXISTS를 사용해 전월 SUCCESS 고객 집합에서 당월 활동 고객을 NULL-safe하게 제외한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘SUCCESS만 활동으로 센다는 가정을 명시한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 current month와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 08 / 13
실제 값 따라가기
같은 입력값이 어느 줄을 지나 어떤 결과가 되는지 추적합니다.
| 순서 | 들어온 값 | 코드가 하는 일 | 나온 값·상태 | 경계 |
|---|---|---|---|---|
| 입력 | previous month | source 계약에 대입 | F07 실행/설명 시작 상태 | workbook 제공 정답이 아니다 |
| 검증 | current month | expected와 actual 또는 형식 대조 | 통과 또는 첫 mismatch | SUCCESS만 활동으로 센다는 가정을 명시한다 |
| 증거 | SUCCESS | marker·hash·row를 같은 run에 연결 | 범위가 적힌 evidence 후보 | 실제 PostgreSQL 실행 결과가 아니다 |
실제 값 — W24-SQL-Q39 — 전월에는 있고 당월에는 없는 고객
-
NOT EXISTS가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 fixture_clock 기준 반개구간과 NOT EXISTS를 사용해 전월 SUCCESS 고객 집합에서 당월 활동 고객을 NULL-safe하게 제외한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘실제 PostgreSQL 실행 결과가 아니다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 NOT EXISTS와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 09 / 13
Gradle·PowerShell·HTTP·PostgreSQL 내부에서 벌어지는 일
Gradle·JUnit XML·PowerShell·HTTP·PostgreSQL·Docker에서 실제로 일어나는 일과 증명 범위를 구분합니다.
W24-SQL-Q39.sql bytes와 expected 값을 읽는다.
파일 존재만으로 runtime 성공은 아니다.native exit·HTTP status·JUnit XML·DB row·hash 중 이 파일이 소유한 값을 만든다.
workbook 제공 정답이 아니다관련 evidence와 사람 의미 검토를 release 후보에 연결한다.
실제 PostgreSQL 실행 결과가 아니다첫 실패 경계 — W24-SQL-Q39 — 전월에는 있고 당월에는 없는 고객
-
half-open range가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 fixture_clock 기준 반개구간과 NOT EXISTS를 사용해 전월 SUCCESS 고객 집합에서 당월 활동 고객을 NULL-safe하게 제외한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘workbook 제공 정답이 아니다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 half-open range와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 10 / 13
흔한 착각과 틀린 예
그럴듯하지만 틀린 해석을 반례로 고칩니다.
❌ previous month 문자열이 source에 있으니 실제 실행도 Green이다.
왜 틀리나 source literal과 runtime 관찰값은 다른 증거다.
바르게 읽기 native exit·actual XML/HTTP/DB evidence를 별도로 확인한다.
반례 script가 실행 전 경로 오류로 멈춰도 literal은 그대로 남는다.
❌ 파일 SHA-256이 있으면 내용의 의미와 사실성도 검증됐다.
왜 틀리나 hash는 동일 bytes만 말한다.
바르게 읽기 schema·수치·질문·근거는 별도 자동 또는 사람 판정을 거친다.
반례 빈 review 질문을 가진 CSV도 안정된 hash를 가진다.
❌ LOCAL_ARTIFACT_VALIDATED는 release Green과 같다.
왜 틀리나 generic validator는 파일 shape만 확인한다.
바르게 읽기 HUMAN_SEMANTIC_REVIEW_REQUIRED를 유지한다.
반례 잘못된 track 점수표도 byte 수 조건은 통과할 수 있다.
❌ 이 파일이 W24 전체 lifecycle을 모두 소유한다.
왜 틀리나 각 source는 Gate·demo·cleanup·사람 review 중 일부만 담당한다.
바르게 읽기 owner와 non-responsibility를 release manifest에서 분리한다.
반례 D4 source audit에는 runtime_claim=false가 명시된다.
❌ 이전 주 Green이나 오래된 log를 현재 commit 결과로 재사용한다.
왜 틀리나 source·commit·actual result가 같은 실행에 묶이지 않는다.
바르게 읽기 release 후보에서 새 evidence와 hash를 만든다.
반례 expected JSON이 바뀌면 예전 XML은 exact inventory를 증명하지 못한다.
STEP 11 / 13
이 코드가 보장하지 않는 것
이 코드가 책임지지 않는 일을 분리합니다.
workbook 제공 정답이 아니다
이 책임을 맡는 곳: runtime GateSUCCESS만 활동으로 센다는 가정을 명시한다
이 책임을 맡는 곳: external/human review실제 PostgreSQL 실행 결과가 아니다
이 책임을 맡는 곳: release manifestworkbook 제공 정답이 아니다
이 책임을 맡는 곳: 운영 환경증명하지 않는 범위 — W24-SQL-Q39 — 전월에는 있고 당월에는 없는 고객
-
SUCCESS가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 fixture_clock 기준 반개구간과 NOT EXISTS를 사용해 전월 SUCCESS 고객 집합에서 당월 활동 고객을 NULL-safe하게 제외한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘SUCCESS만 활동으로 센다는 가정을 명시한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 SUCCESS와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 12 / 13
직접 다시 써보기
뜻 → 조각 → 전체 코드 순서로 다시 씁니다.
1단계 · 뜻부터 복원
- fixture_clock 기준 반개구간과 NOT EXISTS를 사용해 전월 SUCCESS 고객 집합에서 당월 활동 고객을 NULL-safe하게 제외한다.
- 핵심 값은 previous month, current month, NOT EXISTS, half-open range, SUCCESS다.
2단계 · 코드 조각 재조립
- 1. W24-SQL-Q39.sql의 다음 검증 또는 설명 단계를 구성한다
- 2. W24-SQL-Q39.sql의 다음 검증 또는 설명 단계를 구성한다
- 3. W24-SQL-Q39.sql의 다음 검증 또는 설명 단계를 구성한다
- 4. SQL 집합의 입력·변환·필터 단계를 선언한다
- 5. SQL 집합의 입력·변환·필터 단계를 선언한다
- 6. fixture clock을 달 시작 경계로 정규화한다
- 7. fixture clock을 달 시작 경계로 정규화한다
- 8. SQL 집합의 입력·변환·필터 단계를 선언한다
3단계 · 파일 전체 다시 쓰기
illustrative/sql/W24-SQL-Q39.sql을 새 파일에 다시 쓰고 expected·actual·실패·cleanup·비범위를 주석으로 표시한다.
자가 점검
- 비어 있지 않은 모든 source 줄을 한 번씩 읽었나?
- source shape와 runtime Green을 분리했나?
- 사람 검토·외부 상태를 자동 성공으로 꾸미지 않았나?
- 첫 실패와 cleanup 책임을 설명할 수 있나?
STEP 13 / 13
전체 원본 source
감사로 고정한 전체 source를 가감 없이 확인합니다.
학습용 예시 전체 확인하기 · 정본 답안 아님
-- W24-SQL-Q39 학습용 예시이며 workbook 제공 정답이 아니다.
-- 가정: 전월/당월은 fixture_clock.as_of가 속한 달을 기준으로 하고 SUCCESS 거래만 활동으로 센다.
-- 입력 grain: business_tx 한 행 = 거래 한 건. 출력 grain: customer 한 행. 예상 cardinality는 fixture 실행으로 확인한다.
WITH bounds AS (
SELECT
date_trunc('month', as_of) AS current_start,
date_trunc('month', as_of) - INTERVAL '1 month' AS previous_start
FROM fixture_clock
),
previous_customers AS (
SELECT DISTINCT a.customer_id
FROM business_tx AS tx
JOIN account AS a
ON a.account_id = tx.account_id
CROSS JOIN bounds AS b
WHERE tx.status = 'SUCCESS'
AND tx.occurred_at >= b.previous_start
AND tx.occurred_at < b.current_start
)
SELECT
c.customer_id,
c.customer_name
FROM previous_customers AS p
JOIN customer AS c
ON c.customer_id = p.customer_id
WHERE NOT EXISTS (
SELECT 1
FROM account AS a
JOIN business_tx AS tx
ON tx.account_id = a.account_id
CROSS JOIN bounds AS b
WHERE a.customer_id = p.customer_id
AND tx.status = 'SUCCESS'
AND tx.occurred_at >= b.current_start
AND tx.occurred_at < b.current_start + INTERVAL '1 month'
)
ORDER BY c.customer_id;
-- NULL-safe 반례: NOT EXISTS는 subquery에 NULL 값이 있어도 NOT IN처럼 전체 결과가 UNKNOWN으로 오염되지 않는다.
-- 경계 반례: current_start 시각의 거래는 전월이 아니라 당월에 정확히 한 번 포함된다.
08reset-demo.ps1 — 계좌 응답의 numeric ID를 state로 연결
scripts/reset-demo.ps1
PDF 전문 정본 · packaged PowerShell source · 정본 · W24-F0853줄 연결53줄 번역5 chunks
reset-demo.ps1 — 계좌 응답의 numeric ID를 state로 연결
scripts/reset-demo.ps1
PDF 전문 정본 · packaged PowerShell source · 정본 · W24-F08STEP 01 / 13
오늘 이 코드에서 해결할 문제
무엇을 이해해야 하는지 질문부터 잡습니다.
customer-1 인증으로 두 계좌를 만들고 반환된 양의 정수 accountId와 시작 잔액을 비밀 없는 demo-state.json에 저장한다.
- from=10000은 어느 source와 실제 결과에서 확인해야 할까?
- 첫 실패를 만드는 조건과 fail-closed 지점은 어디일까?
- 왜 ‘FCL_DEMO_PASSWORD는 환경변수로만 받는다’를 별도 경계로 남겨야 할까?
from=10000to=5000numeric accountIdDEMO_RESET_OK왜 필요한가 — reset-demo.ps1 — 계좌 응답의 numeric ID를 state로 연결
-
from=10000가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 customer-1 인증으로 두 계좌를 만들고 반환된 양의 정수 accountId와 시작 잔액을 비밀 없는 demo-state.json에 저장한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘FCL_DEMO_PASSWORD는 환경변수로만 받는다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 from=10000와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 02 / 13
아주 짧게: 이 코드는 왜 필요할까?
웹소설 대신 이 코드가 필요한 이유만 두 문단으로 쉽게 봅니다.
새 기능을 멈춘 팀이 코드·test·문서·demo를 같은 release 후보에 묶어 하나씩 검수한다.
검수 도장이 붙은 공통 거래 코어 출고 상자
이 파일은 customer-1 인증으로 두 계좌를 만들고 반환된 양의 정수 accountId와 시작 잔액을 비밀 없는 demo-state.json에 저장한다. 눈으로 읽을 때는 각 줄을 검수표 한 칸처럼 보고, 입력과 다음 상태를 놓치지 않는다.
마지막 도장은 source shape와 실제 runtime·사람 검토를 구분한 뒤에만 찍는다. 특히 FCL_DEMO_PASSWORD는 환경변수로만 받는다
딱 여기까지만 비유는 실행 순서를 돕지만 실제 Gradle·Docker·DB·사람 review를 대신하지 않는다.
STEP 03 / 13
초등학생도 이해하는 설명
생활 비유와 실제 코드의 경계를 함께 확인합니다.
값 1: from=10000
이 파일에서 계속 확인할 고정 단서가 from=10000다.
- 코드 연결
F08 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- FCL_DEMO_PASSWORD는 환경변수로만 받는다
값 2: to=5000
이 파일에서 계속 확인할 고정 단서가 to=5000다.
- 코드 연결
F08 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- 문자열 A/B를 long ID에 넣지 않는다
값 3: numeric accountId
이 파일에서 계속 확인할 고정 단서가 numeric accountId다.
- 코드 연결
F08 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- reset만으로 transfer Green은 아니다
값 4: DEMO_RESET_OK
이 파일에서 계속 확인할 고정 단서가 DEMO_RESET_OK다.
- 코드 연결
F08 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- FCL_DEMO_PASSWORD는 환경변수로만 받는다
STEP 04 / 13
비유 ↔ 코드 전체 연결표
감사 규칙상 연결 대상인 원본 53줄을 빠짐없이 연결합니다.
| 줄 | 정확한 원본 줄 | STARRY 비유 | 실제 뜻·입력·결과·한계 |
|---|---|---|---|
| 1줄F08-L01 | param( |
출고표 1번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 PowerShell script가 받을 입력 계약을 연다.
|
| 2줄F08-L02 | [ |
출고표 2번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 reset-demo.ps1의 다음 검증 또는 설명 단계를 구성한다.
|
| 3줄F08-L03 | [ |
출고표 3번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 reset-demo.ps1의 다음 검증 또는 설명 단계를 구성한다.
|
| 4줄F08-L04 | [ |
출고표 4번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 reset-demo.ps1의 다음 검증 또는 설명 단계를 구성한다.
|
| 5줄F08-L05 | ) |
출고표 5번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 7줄F08-L07 | $ErrorActionPreference = |
출고표 7번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 PowerShell 오류를 계속 진행하지 않고 중단시키는 기본 정책을 둔다.
|
| 8줄F08-L08 | $BaseUrl = |
출고표 8번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 조건·반복·함수의 실행 block을 연다.
|
| 9줄F08-L09 | $BaseUrl |
출고표 9번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 reset-demo.ps1의 다음 검증 또는 설명 단계를 구성한다.
|
| 10줄F08-L10 | } elseif ( |
출고표 10번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 조건·반복·함수의 실행 block을 연다.
|
| 11줄F08-L11 | $env: |
출고표 11번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 reset-demo.ps1의 다음 검증 또는 설명 단계를 구성한다.
|
| 12줄F08-L12 | } else { |
출고표 12번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 조건·반복·함수의 실행 block을 연다.
|
| 13줄F08-L13 | 'http: |
출고표 13번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 reset-demo.ps1의 다음 검증 또는 설명 단계를 구성한다.
|
| 14줄F08-L14 | } |
출고표 14번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 15줄F08-L15 | $user = |
출고표 15번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 16줄F08-L16 | $password = |
출고표 16번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 17줄F08-L17 | if ( |
출고표 17번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 조건·반복·함수의 실행 block을 연다.
|
| 18줄F08-L18 | throw 'Set FCL_DEMO_USER and FCL_DEMO_PASSWORD in this terminal only. |
출고표 18번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 19줄F08-L19 | } |
출고표 19번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 20줄F08-L20 | if ( |
출고표 20번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 조건·반복·함수의 실행 block을 연다.
|
| 21줄F08-L21 | throw 'RunId must be 1-18 ASCII letters, |
출고표 21번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 22줄F08-L22 | } |
출고표 22번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 24줄F08-L24 | $pair = |
출고표 24번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 25줄F08-L25 | $headers = |
출고표 25번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 인증 header를 runtime에서 만들되 evidence에 원문 비밀을 남기지 않는다.
|
| 27줄F08-L27 | function New-DemoAccount( |
출고표 27번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 demo 계좌의 재현 가능한 시작 잔액을 요청 body에 넣는다.
|
| 28줄F08-L28 | $accountNo = |
출고표 28번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 29줄F08-L29 | $body = |
출고표 29번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 demo 계좌의 재현 가능한 시작 잔액을 요청 body에 넣는다.
|
| 30줄F08-L30 | ConvertTo-Json -Compress |
출고표 30번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 검증된 object를 JSON evidence text로 직렬화한다.
|
| 31줄F08-L31 | $response = |
출고표 31번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 HTTP API를 호출해 status와 JSON response를 받는다.
|
| 32줄F08-L32 | -Headers ( |
출고표 32번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 reset-demo.ps1의 다음 검증 또는 설명 단계를 구성한다.
|
| 33줄F08-L33 | -ContentType 'application/ |
출고표 33번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 reset-demo.ps1의 다음 검증 또는 설명 단계를 구성한다.
|
| 34줄F08-L34 | if ( |
출고표 34번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계좌 생성 응답의 numeric ID를 다음 transfer·대사 단계로 전달한다.
|
| 35줄F08-L35 | [ |
출고표 35번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 demo 계좌의 재현 가능한 시작 잔액을 요청 body에 넣는다.
|
| 36줄F08-L36 | throw "account response mismatch: |
출고표 36번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 검증된 object를 JSON evidence text로 직렬화한다.
|
| 37줄F08-L37 | } |
출고표 37번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 38줄F08-L38 | return $response |
출고표 38번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 reset-demo.ps1의 다음 검증 또는 설명 단계를 구성한다.
|
| 39줄F08-L39 | } |
출고표 39번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 41줄F08-L41 | $from = |
출고표 41번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 demo 계좌의 재현 가능한 시작 잔액을 요청 body에 넣는다.
|
| 42줄F08-L42 | $to = |
출고표 42번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 demo 계좌의 재현 가능한 시작 잔액을 요청 body에 넣는다.
|
| 43줄F08-L43 | $state = |
출고표 43번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 조건·반복·함수의 실행 block을 연다.
|
| 44줄F08-L44 | runId = |
출고표 44번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 reset-demo.ps1의 다음 검증 또는 설명 단계를 구성한다.
|
| 45줄F08-L45 | baseUrl = |
출고표 45번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 reset-demo.ps1의 다음 검증 또는 설명 단계를 구성한다.
|
| 46줄F08-L46 | actor = |
출고표 46번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 reset-demo.ps1의 다음 검증 또는 설명 단계를 구성한다.
|
| 47줄F08-L47 | fromAccountId = |
출고표 47번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계좌 생성 응답의 numeric ID를 다음 transfer·대사 단계로 전달한다.
|
| 48줄F08-L48 | toAccountId = |
출고표 48번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계좌 생성 응답의 numeric ID를 다음 transfer·대사 단계로 전달한다.
|
| 49줄F08-L49 | fromOpeningBalance = |
출고표 49번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 demo 계좌의 재현 가능한 시작 잔액을 요청 body에 넣는다.
|
| 50줄F08-L50 | toOpeningBalance = |
출고표 50번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 demo 계좌의 재현 가능한 시작 잔액을 요청 body에 넣는다.
|
| 51줄F08-L51 | } |
출고표 51번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 52줄F08-L52 | $parent = |
출고표 52번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 53줄F08-L53 | if ( |
출고표 53번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 조건·반복·함수의 실행 block을 연다.
|
| 54줄F08-L54 | New-Item -ItemType Directory -Force -Path $parent | Out-Null |
출고표 54번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 Markdown 표 또는 PowerShell pipeline에서 값을 열이나 다음 명령으로 연결한다.
|
| 55줄F08-L55 | } |
출고표 55번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 56줄F08-L56 | $state | ConvertTo-Json | Set-Content -LiteralPath $StatePath -Encoding utf8 |
출고표 56번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 검증된 object를 JSON evidence text로 직렬화한다.
|
| 57줄F08-L57 | "DEMO_RESET_OK runId= |
출고표 57번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계좌 생성 응답의 numeric ID를 다음 transfer·대사 단계로 전달한다.
|
STEP 05 / 13
원본 코드 조각
원본을 5개 의미 조각으로 나누어 그대로 확인합니다.
파일을 한꺼번에 외우지 않고 실행 의미가 이어지는 작은 조각으로 봅니다. 아래 코드는 hash로 고정한 native 정본 source에서 그대로 잘랐습니다.
param(
[string]$RunId = "w24-$([DateTimeOffset]::UtcNow.ToUnixTimeMilliseconds())",
[string]$StatePath = 'evidence\w24\demo-state.json',
[string]$BaseUrl = ''
)
$ErrorActionPreference = 'Stop'
$BaseUrl = if (-not [string]::IsNullOrWhiteSpace($BaseUrl)) {
$BaseUrl
} elseif (-not [string]::IsNullOrWhiteSpace($env:FCL_BASE_URL)) {
$env:FCL_BASE_URL
} else {
'http://localhost:8080'
}
$user = $env:FCL_DEMO_USER
$password = $env:FCL_DEMO_PASSWORD
if ([string]::IsNullOrWhiteSpace($user) -or [string]::IsNullOrWhiteSpace($password)) {
throw 'Set FCL_DEMO_USER and FCL_DEMO_PASSWORD in this terminal only.'
}
if ($RunId -notmatch '^[A-Za-z0-9-]{1,18}$') {
throw 'RunId must be 1-18 ASCII letters, digits, or hyphens.'
}
$pair = [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes("${user}:${password}"))
$headers = @{ Authorization = "Basic $pair" }
function New-DemoAccount([string]$Suffix, [long]$OpeningBalance) {
$accountNo = "DEMO-$RunId-$Suffix"
$body = @{ accountNo = $accountNo; openingBalance = $OpeningBalance } |
ConvertTo-Json -Compress
$response = Invoke-RestMethod -Method Post -Uri "$BaseUrl/api/accounts" `
-Headers ($headers + @{ 'X-Request-Id' = "w24-open-$Suffix-$RunId" }) `
-ContentType 'application/json' -Body $body
if ([long]$response.accountId -le 0 -or $response.accountNo -cne $accountNo -or
[long]$response.balance -ne $OpeningBalance) {
throw "account response mismatch: $($response | ConvertTo-Json -Compress)"
}
return $response
}
$from = New-DemoAccount -Suffix 'FROM' -OpeningBalance 10000
$to = New-DemoAccount -Suffix 'TO' -OpeningBalance 5000
$state = [ordered]@{
runId = $RunId
baseUrl = $BaseUrl
actor = $user
fromAccountId = [long]$from.accountId
toAccountId = [long]$to.accountId
fromOpeningBalance = 10000
toOpeningBalance = 5000
}
$parent = Split-Path -Parent $StatePath
if (-not [string]::IsNullOrWhiteSpace($parent)) {
New-Item -ItemType Directory -Force -Path $parent | Out-Null
}
$state | ConvertTo-Json | Set-Content -LiteralPath $StatePath -Encoding utf8
"DEMO_RESET_OK runId=$RunId from=$($state.fromAccountId) to=$($state.toAccountId)"
STEP 06 / 13
코드 한 줄씩 한국어로 번역
비어 있지 않은 53줄을 모두 한국어로 옮깁니다.
비어 있지 않은 원본 줄은 하나도 생략하지 않습니다.
| 줄 | 원본 | 한국어 번역 |
|---|---|---|
| 1 | param( | 실행 의미: PowerShell script가 받을 입력 계약을 연다. |
| 2 | [string]$RunId = "w24-$([DateTimeOffset]::UtcNow.ToUnixTimeMilliseconds())", | 실행 의미: reset-demo.ps1의 다음 검증 또는 설명 단계를 구성한다. |
| 3 | [string]$StatePath = 'evidence\w24\demo-state.json', | 실행 의미: reset-demo.ps1의 다음 검증 또는 설명 단계를 구성한다. |
| 4 | [string]$BaseUrl = '' | 실행 의미: reset-demo.ps1의 다음 검증 또는 설명 단계를 구성한다. |
| 5 | ) | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 7 | $ErrorActionPreference = 'Stop' | 실행 의미: PowerShell 오류를 계속 진행하지 않고 중단시키는 기본 정책을 둔다. |
| 8 | $BaseUrl = if (-not [string]::IsNullOrWhiteSpace($BaseUrl)) { | 실행 의미: 조건·반복·함수의 실행 block을 연다. |
| 9 | $BaseUrl | 실행 의미: reset-demo.ps1의 다음 검증 또는 설명 단계를 구성한다. |
| 10 | } elseif (-not [string]::IsNullOrWhiteSpace($env:FCL_BASE_URL)) { | 실행 의미: 조건·반복·함수의 실행 block을 연다. |
| 11 | $env:FCL_BASE_URL | 실행 의미: reset-demo.ps1의 다음 검증 또는 설명 단계를 구성한다. |
| 12 | } else { | 실행 의미: 조건·반복·함수의 실행 block을 연다. |
| 13 | 'http://localhost:8080' | 실행 의미: reset-demo.ps1의 다음 검증 또는 설명 단계를 구성한다. |
| 14 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 15 | $user = $env:FCL_DEMO_USER | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 16 | $password = $env:FCL_DEMO_PASSWORD | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 17 | if ([string]::IsNullOrWhiteSpace($user) -or [string]::IsNullOrWhiteSpace($password)) { | 실행 의미: 조건·반복·함수의 실행 block을 연다. |
| 18 | throw 'Set FCL_DEMO_USER and FCL_DEMO_PASSWORD in this terminal only.' | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 19 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 20 | if ($RunId -notmatch '^[A-Za-z0-9-]{1,18}$') { | 실행 의미: 조건·반복·함수의 실행 block을 연다. |
| 21 | throw 'RunId must be 1-18 ASCII letters, digits, or hyphens.' | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 22 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 24 | $pair = [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes("${user}:${password}")) | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 25 | $headers = @{ Authorization = "Basic $pair" } | 실행 의미: 인증 header를 runtime에서 만들되 evidence에 원문 비밀을 남기지 않는다. |
| 27 | function New-DemoAccount([string]$Suffix, [long]$OpeningBalance) { | 실행 의미: demo 계좌의 재현 가능한 시작 잔액을 요청 body에 넣는다. |
| 28 | $accountNo = "DEMO-$RunId-$Suffix" | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 29 | $body = @{ accountNo = $accountNo; openingBalance = $OpeningBalance } | | 실행 의미: demo 계좌의 재현 가능한 시작 잔액을 요청 body에 넣는다. |
| 30 | ConvertTo-Json -Compress | 실행 의미: 검증된 object를 JSON evidence text로 직렬화한다. |
| 31 | $response = Invoke-RestMethod -Method Post -Uri "$BaseUrl/api/accounts" ` | 실행 의미: HTTP API를 호출해 status와 JSON response를 받는다. |
| 32 | -Headers ($headers + @{ 'X-Request-Id' = "w24-open-$Suffix-$RunId" }) ` | 실행 의미: reset-demo.ps1의 다음 검증 또는 설명 단계를 구성한다. |
| 33 | -ContentType 'application/json' -Body $body | 실행 의미: reset-demo.ps1의 다음 검증 또는 설명 단계를 구성한다. |
| 34 | if ([long]$response.accountId -le 0 -or $response.accountNo -cne $accountNo -or | 실행 의미: 계좌 생성 응답의 numeric ID를 다음 transfer·대사 단계로 전달한다. |
| 35 | [long]$response.balance -ne $OpeningBalance) { | 실행 의미: demo 계좌의 재현 가능한 시작 잔액을 요청 body에 넣는다. |
| 36 | throw "account response mismatch: $($response | ConvertTo-Json -Compress)" | 실행 의미: 검증된 object를 JSON evidence text로 직렬화한다. |
| 37 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 38 | return $response | 실행 의미: reset-demo.ps1의 다음 검증 또는 설명 단계를 구성한다. |
| 39 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 41 | $from = New-DemoAccount -Suffix 'FROM' -OpeningBalance 10000 | 실행 의미: demo 계좌의 재현 가능한 시작 잔액을 요청 body에 넣는다. |
| 42 | $to = New-DemoAccount -Suffix 'TO' -OpeningBalance 5000 | 실행 의미: demo 계좌의 재현 가능한 시작 잔액을 요청 body에 넣는다. |
| 43 | $state = [ordered]@{ | 실행 의미: 조건·반복·함수의 실행 block을 연다. |
| 44 | runId = $RunId | 실행 의미: reset-demo.ps1의 다음 검증 또는 설명 단계를 구성한다. |
| 45 | baseUrl = $BaseUrl | 실행 의미: reset-demo.ps1의 다음 검증 또는 설명 단계를 구성한다. |
| 46 | actor = $user | 실행 의미: reset-demo.ps1의 다음 검증 또는 설명 단계를 구성한다. |
| 47 | fromAccountId = [long]$from.accountId | 실행 의미: 계좌 생성 응답의 numeric ID를 다음 transfer·대사 단계로 전달한다. |
| 48 | toAccountId = [long]$to.accountId | 실행 의미: 계좌 생성 응답의 numeric ID를 다음 transfer·대사 단계로 전달한다. |
| 49 | fromOpeningBalance = 10000 | 실행 의미: demo 계좌의 재현 가능한 시작 잔액을 요청 body에 넣는다. |
| 50 | toOpeningBalance = 5000 | 실행 의미: demo 계좌의 재현 가능한 시작 잔액을 요청 body에 넣는다. |
| 51 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 52 | $parent = Split-Path -Parent $StatePath | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 53 | if (-not [string]::IsNullOrWhiteSpace($parent)) { | 실행 의미: 조건·반복·함수의 실행 block을 연다. |
| 54 | New-Item -ItemType Directory -Force -Path $parent | Out-Null | 실행 의미: Markdown 표 또는 PowerShell pipeline에서 값을 열이나 다음 명령으로 연결한다. |
| 55 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 56 | $state | ConvertTo-Json | Set-Content -LiteralPath $StatePath -Encoding utf8 | 실행 의미: 검증된 object를 JSON evidence text로 직렬화한다. |
| 57 | "DEMO_RESET_OK runId=$RunId from=$($state.fromAccountId) to=$($state.toAccountId)" | 실행 의미: 계좌 생성 응답의 numeric ID를 다음 transfer·대사 단계로 전달한다. |
STEP 07 / 13
기존 수준의 한 줄 읽기·문법 해부
쉬운 설명 다음에 문법과 실행 순서를 정밀하게 읽습니다.
한 줄로 읽기reset-demo.ps1 — 계좌 응답의 numeric ID를 state로 연결는 customer-1 인증으로 두 계좌를 만들고 반환된 양의 정수 accountId와 시작 잔액을 비밀 없는 demo-state.json에 저장한다.
문법 해부
- .ps1 문법에서 선언·조건·pipeline·block 경계를 먼저 나눈다.
- expected 값과 actual 결과를 같은 이름처럼 보여도 서로 다른 source로 읽는다.
- native exit·row count·hash·사람 판정을 서로 대체하지 않는다.
실행 순서
- 입력 경로·fixture·환경변수·expected 계약을 고정한다.
- source가 실행하는 native process·HTTP·SQL 또는 형식 검사를 따라간다.
- actual 값과 exact marker를 대조하고 실패면 성공 발행 전에 중단한다.
- finally cleanup과 비범위를 evidence에 남긴다.
W24 조각별 정밀 해설
F08-C01 · 원문 1–12줄
- 문법 해부
- .ps1 문법으로 1–12줄의 선언·조건·pipeline·block을 나눈다.
- 실제 값 추적
- from=10000, to=5000, numeric accountId를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- expected와 actual이 일치하고 owner evidence가 같은 run/hash에 연결되는 경우다.
- 틀린 예·반례
- FCL_DEMO_PASSWORD는 환경변수로만 받는다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- 파일 존재·문자열·hash·exit0 하나를 의미 Green 전체와 같다고 보지 않는다.
- 하지 않는 일
- FCL_DEMO_PASSWORD는 환경변수로만 받는다; 문자열 A/B를 long ID에 넣지 않는다; reset만으로 transfer Green은 아니다
- 다음 연결
- 다음 조각 또는 F08 evidence 판정으로 상태를 넘긴다.
F08-C02 · 원문 13–24줄
- 문법 해부
- .ps1 문법으로 13–24줄의 선언·조건·pipeline·block을 나눈다.
- 실제 값 추적
- from=10000, to=5000, numeric accountId를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- expected와 actual이 일치하고 owner evidence가 같은 run/hash에 연결되는 경우다.
- 틀린 예·반례
- FCL_DEMO_PASSWORD는 환경변수로만 받는다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- 파일 존재·문자열·hash·exit0 하나를 의미 Green 전체와 같다고 보지 않는다.
- 하지 않는 일
- FCL_DEMO_PASSWORD는 환경변수로만 받는다; 문자열 A/B를 long ID에 넣지 않는다; reset만으로 transfer Green은 아니다
- 다음 연결
- 다음 조각 또는 F08 evidence 판정으로 상태를 넘긴다.
F08-C03 · 원문 25–36줄
- 문법 해부
- .ps1 문법으로 25–36줄의 선언·조건·pipeline·block을 나눈다.
- 실제 값 추적
- from=10000, to=5000, numeric accountId를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- expected와 actual이 일치하고 owner evidence가 같은 run/hash에 연결되는 경우다.
- 틀린 예·반례
- FCL_DEMO_PASSWORD는 환경변수로만 받는다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- 파일 존재·문자열·hash·exit0 하나를 의미 Green 전체와 같다고 보지 않는다.
- 하지 않는 일
- FCL_DEMO_PASSWORD는 환경변수로만 받는다; 문자열 A/B를 long ID에 넣지 않는다; reset만으로 transfer Green은 아니다
- 다음 연결
- 다음 조각 또는 F08 evidence 판정으로 상태를 넘긴다.
F08-C04 · 원문 37–48줄
- 문법 해부
- .ps1 문법으로 37–48줄의 선언·조건·pipeline·block을 나눈다.
- 실제 값 추적
- from=10000, to=5000, numeric accountId를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- expected와 actual이 일치하고 owner evidence가 같은 run/hash에 연결되는 경우다.
- 틀린 예·반례
- FCL_DEMO_PASSWORD는 환경변수로만 받는다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- 파일 존재·문자열·hash·exit0 하나를 의미 Green 전체와 같다고 보지 않는다.
- 하지 않는 일
- FCL_DEMO_PASSWORD는 환경변수로만 받는다; 문자열 A/B를 long ID에 넣지 않는다; reset만으로 transfer Green은 아니다
- 다음 연결
- 다음 조각 또는 F08 evidence 판정으로 상태를 넘긴다.
F08-C05 · 원문 49–57줄
- 문법 해부
- .ps1 문법으로 49–57줄의 선언·조건·pipeline·block을 나눈다.
- 실제 값 추적
- from=10000, to=5000, numeric accountId를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- expected와 actual이 일치하고 owner evidence가 같은 run/hash에 연결되는 경우다.
- 틀린 예·반례
- FCL_DEMO_PASSWORD는 환경변수로만 받는다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- 파일 존재·문자열·hash·exit0 하나를 의미 Green 전체와 같다고 보지 않는다.
- 하지 않는 일
- FCL_DEMO_PASSWORD는 환경변수로만 받는다; 문자열 A/B를 long ID에 넣지 않는다; reset만으로 transfer Green은 아니다
- 다음 연결
- 다음 조각 또는 F08 evidence 판정으로 상태를 넘긴다.
실행 순서 — reset-demo.ps1 — 계좌 응답의 numeric ID를 state로 연결
-
to=5000가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 customer-1 인증으로 두 계좌를 만들고 반환된 양의 정수 accountId와 시작 잔액을 비밀 없는 demo-state.json에 저장한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘문자열 A/B를 long ID에 넣지 않는다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 to=5000와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 08 / 13
실제 값 따라가기
같은 입력값이 어느 줄을 지나 어떤 결과가 되는지 추적합니다.
| 순서 | 들어온 값 | 코드가 하는 일 | 나온 값·상태 | 경계 |
|---|---|---|---|---|
| 입력 | from=10000 | source 계약에 대입 | F08 실행/설명 시작 상태 | FCL_DEMO_PASSWORD는 환경변수로만 받는다 |
| 검증 | to=5000 | expected와 actual 또는 형식 대조 | 통과 또는 첫 mismatch | 문자열 A/B를 long ID에 넣지 않는다 |
| 증거 | DEMO_RESET_OK | marker·hash·row를 같은 run에 연결 | 범위가 적힌 evidence 후보 | reset만으로 transfer Green은 아니다 |
실제 값 — reset-demo.ps1 — 계좌 응답의 numeric ID를 state로 연결
-
numeric accountId가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 customer-1 인증으로 두 계좌를 만들고 반환된 양의 정수 accountId와 시작 잔액을 비밀 없는 demo-state.json에 저장한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘reset만으로 transfer Green은 아니다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 numeric accountId와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 09 / 13
Gradle·PowerShell·HTTP·PostgreSQL 내부에서 벌어지는 일
Gradle·JUnit XML·PowerShell·HTTP·PostgreSQL·Docker에서 실제로 일어나는 일과 증명 범위를 구분합니다.
reset-demo.ps1 bytes와 expected 값을 읽는다.
파일 존재만으로 runtime 성공은 아니다.native exit·HTTP status·JUnit XML·DB row·hash 중 이 파일이 소유한 값을 만든다.
FCL_DEMO_PASSWORD는 환경변수로만 받는다관련 evidence와 사람 의미 검토를 release 후보에 연결한다.
reset만으로 transfer Green은 아니다첫 실패 경계 — reset-demo.ps1 — 계좌 응답의 numeric ID를 state로 연결
-
DEMO_RESET_OK가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 customer-1 인증으로 두 계좌를 만들고 반환된 양의 정수 accountId와 시작 잔액을 비밀 없는 demo-state.json에 저장한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘FCL_DEMO_PASSWORD는 환경변수로만 받는다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 DEMO_RESET_OK와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 10 / 13
흔한 착각과 틀린 예
그럴듯하지만 틀린 해석을 반례로 고칩니다.
❌ from=10000 문자열이 source에 있으니 실제 실행도 Green이다.
왜 틀리나 source literal과 runtime 관찰값은 다른 증거다.
바르게 읽기 native exit·actual XML/HTTP/DB evidence를 별도로 확인한다.
반례 script가 실행 전 경로 오류로 멈춰도 literal은 그대로 남는다.
❌ 파일 SHA-256이 있으면 내용의 의미와 사실성도 검증됐다.
왜 틀리나 hash는 동일 bytes만 말한다.
바르게 읽기 schema·수치·질문·근거는 별도 자동 또는 사람 판정을 거친다.
반례 빈 review 질문을 가진 CSV도 안정된 hash를 가진다.
❌ LOCAL_ARTIFACT_VALIDATED는 release Green과 같다.
왜 틀리나 generic validator는 파일 shape만 확인한다.
바르게 읽기 HUMAN_SEMANTIC_REVIEW_REQUIRED를 유지한다.
반례 잘못된 track 점수표도 byte 수 조건은 통과할 수 있다.
❌ 이 파일이 W24 전체 lifecycle을 모두 소유한다.
왜 틀리나 각 source는 Gate·demo·cleanup·사람 review 중 일부만 담당한다.
바르게 읽기 owner와 non-responsibility를 release manifest에서 분리한다.
반례 D4 source audit에는 runtime_claim=false가 명시된다.
❌ 이전 주 Green이나 오래된 log를 현재 commit 결과로 재사용한다.
왜 틀리나 source·commit·actual result가 같은 실행에 묶이지 않는다.
바르게 읽기 release 후보에서 새 evidence와 hash를 만든다.
반례 expected JSON이 바뀌면 예전 XML은 exact inventory를 증명하지 못한다.
STEP 11 / 13
이 코드가 보장하지 않는 것
이 코드가 책임지지 않는 일을 분리합니다.
FCL_DEMO_PASSWORD는 환경변수로만 받는다
이 책임을 맡는 곳: runtime Gate문자열 A/B를 long ID에 넣지 않는다
이 책임을 맡는 곳: external/human reviewreset만으로 transfer Green은 아니다
이 책임을 맡는 곳: release manifestFCL_DEMO_PASSWORD는 환경변수로만 받는다
이 책임을 맡는 곳: 운영 환경증명하지 않는 범위 — reset-demo.ps1 — 계좌 응답의 numeric ID를 state로 연결
-
from=10000가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 customer-1 인증으로 두 계좌를 만들고 반환된 양의 정수 accountId와 시작 잔액을 비밀 없는 demo-state.json에 저장한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘문자열 A/B를 long ID에 넣지 않는다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 from=10000와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 12 / 13
직접 다시 써보기
뜻 → 조각 → 전체 코드 순서로 다시 씁니다.
1단계 · 뜻부터 복원
- customer-1 인증으로 두 계좌를 만들고 반환된 양의 정수 accountId와 시작 잔액을 비밀 없는 demo-state.json에 저장한다.
- 핵심 값은 from=10000, to=5000, numeric accountId, DEMO_RESET_OK다.
2단계 · 코드 조각 재조립
- 1. PowerShell script가 받을 입력 계약을 연다
- 2. reset-demo.ps1의 다음 검증 또는 설명 단계를 구성한다
- 3. reset-demo.ps1의 다음 검증 또는 설명 단계를 구성한다
- 4. reset-demo.ps1의 다음 검증 또는 설명 단계를 구성한다
- 5. 앞에서 연 block 또는 호출 범위를 닫는다
- 7. PowerShell 오류를 계속 진행하지 않고 중단시키는 기본 정책을 둔다
- 8. 조건·반복·함수의 실행 block을 연다
- 9. reset-demo.ps1의 다음 검증 또는 설명 단계를 구성한다
3단계 · 파일 전체 다시 쓰기
scripts/reset-demo.ps1을 새 파일에 다시 쓰고 expected·actual·실패·cleanup·비범위를 주석으로 표시한다.
자가 점검
- 비어 있지 않은 모든 source 줄을 한 번씩 읽었나?
- source shape와 runtime Green을 분리했나?
- 사람 검토·외부 상태를 자동 성공으로 꾸미지 않았나?
- 첫 실패와 cleanup 책임을 설명할 수 있나?
STEP 13 / 13
전체 원본 source
감사로 고정한 전체 source를 가감 없이 확인합니다.
원문 정본 전체 source 확인하기
param(
[string]$RunId = "w24-$([DateTimeOffset]::UtcNow.ToUnixTimeMilliseconds())",
[string]$StatePath = 'evidence\w24\demo-state.json',
[string]$BaseUrl = ''
)
$ErrorActionPreference = 'Stop'
$BaseUrl = if (-not [string]::IsNullOrWhiteSpace($BaseUrl)) {
$BaseUrl
} elseif (-not [string]::IsNullOrWhiteSpace($env:FCL_BASE_URL)) {
$env:FCL_BASE_URL
} else {
'http://localhost:8080'
}
$user = $env:FCL_DEMO_USER
$password = $env:FCL_DEMO_PASSWORD
if ([string]::IsNullOrWhiteSpace($user) -or [string]::IsNullOrWhiteSpace($password)) {
throw 'Set FCL_DEMO_USER and FCL_DEMO_PASSWORD in this terminal only.'
}
if ($RunId -notmatch '^[A-Za-z0-9-]{1,18}$') {
throw 'RunId must be 1-18 ASCII letters, digits, or hyphens.'
}
$pair = [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes("${user}:${password}"))
$headers = @{ Authorization = "Basic $pair" }
function New-DemoAccount([string]$Suffix, [long]$OpeningBalance) {
$accountNo = "DEMO-$RunId-$Suffix"
$body = @{ accountNo = $accountNo; openingBalance = $OpeningBalance } |
ConvertTo-Json -Compress
$response = Invoke-RestMethod -Method Post -Uri "$BaseUrl/api/accounts" `
-Headers ($headers + @{ 'X-Request-Id' = "w24-open-$Suffix-$RunId" }) `
-ContentType 'application/json' -Body $body
if ([long]$response.accountId -le 0 -or $response.accountNo -cne $accountNo -or
[long]$response.balance -ne $OpeningBalance) {
throw "account response mismatch: $($response | ConvertTo-Json -Compress)"
}
return $response
}
$from = New-DemoAccount -Suffix 'FROM' -OpeningBalance 10000
$to = New-DemoAccount -Suffix 'TO' -OpeningBalance 5000
$state = [ordered]@{
runId = $RunId
baseUrl = $BaseUrl
actor = $user
fromAccountId = [long]$from.accountId
toAccountId = [long]$to.accountId
fromOpeningBalance = 10000
toOpeningBalance = 5000
}
$parent = Split-Path -Parent $StatePath
if (-not [string]::IsNullOrWhiteSpace($parent)) {
New-Item -ItemType Directory -Force -Path $parent | Out-Null
}
$state | ConvertTo-Json | Set-Content -LiteralPath $StatePath -Encoding utf8
"DEMO_RESET_OK runId=$RunId from=$($state.fromAccountId) to=$($state.toAccountId)"
09run-transfer.ps1 — canonical JSON과 201·200·409 계약
scripts/run-transfer.ps1
PDF 전문 정본 · packaged PowerShell source · 정본 · W24-F0958줄 연결58줄 번역6 chunks
run-transfer.ps1 — canonical JSON과 201·200·409 계약
scripts/run-transfer.ps1
PDF 전문 정본 · packaged PowerShell source · 정본 · W24-F09STEP 01 / 13
오늘 이 코드에서 해결할 문제
무엇을 이해해야 하는지 질문부터 잡습니다.
state의 numeric accountId로 transfer JSON을 만들고 idempotency key·amount별 예상 HTTP status와 response를 기록한다.
- 201 first은 어느 source와 실제 결과에서 확인해야 할까?
- 첫 실패를 만드는 조건과 fail-closed 지점은 어디일까?
- 왜 ‘reset state가 없거나 ID가 잘못되면 실패한다’를 별도 경계로 남겨야 할까?
201 first200 replay409 conflictamount 1000/2000왜 필요한가 — run-transfer.ps1 — canonical JSON과 201·200·409 계약
-
201 first가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 state의 numeric accountId로 transfer JSON을 만들고 idempotency key·amount별 예상 HTTP status와 response를 기록한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘reset state가 없거나 ID가 잘못되면 실패한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 201 first와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 02 / 13
아주 짧게: 이 코드는 왜 필요할까?
웹소설 대신 이 코드가 필요한 이유만 두 문단으로 쉽게 봅니다.
새 기능을 멈춘 팀이 코드·test·문서·demo를 같은 release 후보에 묶어 하나씩 검수한다.
검수 도장이 붙은 공통 거래 코어 출고 상자
이 파일은 state의 numeric accountId로 transfer JSON을 만들고 idempotency key·amount별 예상 HTTP status와 response를 기록한다. 눈으로 읽을 때는 각 줄을 검수표 한 칸처럼 보고, 입력과 다음 상태를 놓치지 않는다.
마지막 도장은 source shape와 실제 runtime·사람 검토를 구분한 뒤에만 찍는다. 특히 reset state가 없거나 ID가 잘못되면 실패한다
딱 여기까지만 비유는 실행 순서를 돕지만 실제 Gradle·Docker·DB·사람 review를 대신하지 않는다.
STEP 03 / 13
초등학생도 이해하는 설명
생활 비유와 실제 코드의 경계를 함께 확인합니다.
값 1: 201 first
이 파일에서 계속 확인할 고정 단서가 201 first다.
- 코드 연결
F09 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- reset state가 없거나 ID가 잘못되면 실패한다
값 2: 200 replay
이 파일에서 계속 확인할 고정 단서가 200 replay다.
- 코드 연결
F09 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- 비밀번호 원문을 evidence에 쓰지 않는다
값 3: 409 conflict
이 파일에서 계속 확인할 고정 단서가 409 conflict다.
- 코드 연결
F09 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- DB 대사는 별도 script 책임이다
값 4: amount 1000/2000
이 파일에서 계속 확인할 고정 단서가 amount 1000/2000다.
- 코드 연결
F09 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- reset state가 없거나 ID가 잘못되면 실패한다
STEP 04 / 13
비유 ↔ 코드 전체 연결표
감사 규칙상 연결 대상인 원본 58줄을 빠짐없이 연결합니다.
| 줄 | 정확한 원본 줄 | STARRY 비유 | 실제 뜻·입력·결과·한계 |
|---|---|---|---|
| 1줄F09-L01 | param( |
출고표 1번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 PowerShell script가 받을 입력 계약을 연다.
|
| 2줄F09-L02 | [ |
출고표 2번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 이 인자가 빠지면 실행 시작 전에 binding을 거절한다.
|
| 3줄F09-L03 | [ |
출고표 3번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 이 인자가 빠지면 실행 시작 전에 binding을 거절한다.
|
| 4줄F09-L04 | [ |
출고표 4번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 이 인자가 빠지면 실행 시작 전에 binding을 거절한다.
|
| 5줄F09-L05 | [ |
출고표 5번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 run-transfer.ps1의 다음 검증 또는 설명 단계를 구성한다.
|
| 6줄F09-L06 | ) |
출고표 6번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 8줄F09-L08 | $ErrorActionPreference = |
출고표 8번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 PowerShell 오류를 계속 진행하지 않고 중단시키는 기본 정책을 둔다.
|
| 9줄F09-L09 | $user = |
출고표 9번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 10줄F09-L10 | $password = |
출고표 10번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 11줄F09-L11 | if ( |
출고표 11번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 조건·반복·함수의 실행 block을 연다.
|
| 12줄F09-L12 | throw 'Set FCL_DEMO_USER and FCL_DEMO_PASSWORD in this terminal only. |
출고표 12번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 13줄F09-L13 | } |
출고표 13번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 14줄F09-L14 | if ( |
출고표 14번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 필수 파일이나 경로가 실제로 있는지 확인한다.
|
| 15줄F09-L15 | throw "Run reset-demo. |
출고표 15번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 16줄F09-L16 | } |
출고표 16번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 17줄F09-L17 | $state = |
출고표 17번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 JSON text를 필드로 접근 가능한 PowerShell object로 바꾼다.
|
| 18줄F09-L18 | if ( |
출고표 18번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계좌 생성 응답의 numeric ID를 다음 transfer·대사 단계로 전달한다.
|
| 19줄F09-L19 | throw 'demo state has invalid numeric account IDs' |
출고표 19번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 20줄F09-L20 | } |
출고표 20번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 22줄F09-L22 | $pair = |
출고표 22번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 23줄F09-L23 | $headers = |
출고표 23번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 인증 header를 runtime에서 만들되 evidence에 원문 비밀을 남기지 않는다.
|
| 24줄F09-L24 | $payload = |
출고표 24번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 조건·반복·함수의 실행 block을 연다.
|
| 25줄F09-L25 | transactionId = |
출고표 25번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 run-transfer.ps1의 다음 검증 또는 설명 단계를 구성한다.
|
| 26줄F09-L26 | fromAccountId = |
출고표 26번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계좌 생성 응답의 numeric ID를 다음 transfer·대사 단계로 전달한다.
|
| 27줄F09-L27 | toAccountId = |
출고표 27번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계좌 생성 응답의 numeric ID를 다음 transfer·대사 단계로 전달한다.
|
| 28줄F09-L28 | amount = |
출고표 28번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 run-transfer.ps1의 다음 검증 또는 설명 단계를 구성한다.
|
| 29줄F09-L29 | } | ConvertTo-Json -Compress |
출고표 29번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 검증된 object를 JSON evidence text로 직렬화한다.
|
| 31줄F09-L31 | $status = |
출고표 31번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 32줄F09-L32 | $body = |
출고표 32번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 33줄F09-L33 | try { |
출고표 33번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 조건·반복·함수의 실행 block을 연다.
|
| 34줄F09-L34 | $response = |
출고표 34번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 35줄F09-L35 | -Headers $headers -ContentType 'application/ |
출고표 35번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 run-transfer.ps1의 다음 검증 또는 설명 단계를 구성한다.
|
| 36줄F09-L36 | $status = |
출고표 36번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 37줄F09-L37 | $body = |
출고표 37번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 38줄F09-L38 | } catch { |
출고표 38번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 실패 object를 보존해 cleanup 뒤 다시 실패시키도록 잡는다.
|
| 39줄F09-L39 | $httpResponse = |
출고표 39번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 40줄F09-L40 | if ( |
출고표 40번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 41줄F09-L41 | $status = |
출고표 41번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 42줄F09-L42 | $stream = |
출고표 42번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 43줄F09-L43 | $reader = |
출고표 43번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 44줄F09-L44 | try { |
출고표 44번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 중간 실패가 있어도 반드시 실행할 cleanup 경계를 연다.
|
| 45줄F09-L45 | } |
출고표 45번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 47줄F09-L47 | if ( |
출고표 47번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 각 demo 단계가 반드시 반환해야 할 HTTP status를 입력으로 고정한다.
|
| 48줄F09-L48 | throw "unexpected transfer status expected= |
출고표 48번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 각 demo 단계가 반드시 반환해야 할 HTTP status를 입력으로 고정한다.
|
| 49줄F09-L49 | } |
출고표 49번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 50줄F09-L50 | $json = |
출고표 50번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 JSON text를 필드로 접근 가능한 PowerShell object로 바꾼다.
|
| 51줄F09-L51 | if ( |
출고표 51번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 각 demo 단계가 반드시 반환해야 할 HTTP status를 입력으로 고정한다.
|
| 52줄F09-L52 | if ( |
출고표 52번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 조건·반복·함수의 실행 block을 연다.
|
| 53줄F09-L53 | throw "first response contract mismatch: |
출고표 53번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 54줄F09-L54 | } |
출고표 54번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 55줄F09-L55 | } elseif ( |
출고표 55번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 각 demo 단계가 반드시 반환해야 할 HTTP status를 입력으로 고정한다.
|
| 56줄F09-L56 | if ( |
출고표 56번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 조건·반복·함수의 실행 block을 연다.
|
| 57줄F09-L57 | throw "replay response contract mismatch: |
출고표 57번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 58줄F09-L58 | } |
출고표 58번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 59줄F09-L59 | } elseif ( |
출고표 59번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 같은 actor·operation·key의 요청을 최초·replay·conflict로 구분한다.
|
| 60줄F09-L60 | throw "conflict response contract mismatch: |
출고표 60번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 61줄F09-L61 | } |
출고표 61번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 62줄F09-L62 | "DEMO_TRANSFER_OK key= |
출고표 62번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 한 transfer 호출이 기대 status와 일치했음을 transcript에 남긴다.
|
STEP 05 / 13
원본 코드 조각
원본을 6개 의미 조각으로 나누어 그대로 확인합니다.
파일을 한꺼번에 외우지 않고 실행 의미가 이어지는 작은 조각으로 봅니다. 아래 코드는 hash로 고정한 native 정본 source에서 그대로 잘랐습니다.
param(
[Parameter(Mandatory=$true)][string]$Key,
[Parameter(Mandatory=$true)][long]$Amount,
[Parameter(Mandatory=$true)][ValidateSet(200, 201, 409)][int]$ExpectedStatus,
[string]$StatePath = 'evidence\w24\demo-state.json'
)
$ErrorActionPreference = 'Stop'
$user = $env:FCL_DEMO_USER
$password = $env:FCL_DEMO_PASSWORD
if ([string]::IsNullOrWhiteSpace($user) -or [string]::IsNullOrWhiteSpace($password)) {
throw 'Set FCL_DEMO_USER and FCL_DEMO_PASSWORD in this terminal only.'
}
if (!(Test-Path -LiteralPath $StatePath -PathType Leaf)) {
throw "Run reset-demo.ps1 first; missing state: $StatePath"
}
$state = Get-Content -LiteralPath $StatePath -Raw | ConvertFrom-Json
if ([long]$state.fromAccountId -le 0 -or [long]$state.toAccountId -le 0) {
throw 'demo state has invalid numeric account IDs'
}
$pair = [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes("${user}:${password}"))
$headers = @{ Authorization = "Basic $pair"; 'X-Request-Id' = "w24-transfer-$Key-$Amount" }
$payload = @{
transactionId = $Key
fromAccountId = [long]$state.fromAccountId
toAccountId = [long]$state.toAccountId
amount = $Amount
} | ConvertTo-Json -Compress
$status = 0
$body = ''
try {
$response = Invoke-WebRequest -UseBasicParsing -Method Post -Uri "$($state.baseUrl)/api/transfers" `
-Headers $headers -ContentType 'application/json' -Body $payload
$status = [int]$response.StatusCode
$body = [string]$response.Content
} catch {
$httpResponse = $_.Exception.Response
if ($null -eq $httpResponse) { throw }
$status = [int]$httpResponse.StatusCode
$stream = $httpResponse.GetResponseStream()
$reader = New-Object System.IO.StreamReader($stream)
try { $body = $reader.ReadToEnd() } finally { $reader.Dispose(); $stream.Dispose() }
}
if ($status -ne $ExpectedStatus) {
throw "unexpected transfer status expected=$ExpectedStatus actual=$status body=$body"
}
$json = $body | ConvertFrom-Json
if ($ExpectedStatus -eq 201) {
if ($json.transactionId -cne $Key -or $json.status -cne 'COMPLETED' -or [bool]$json.replayed) {
throw "first response contract mismatch: $body"
}
} elseif ($ExpectedStatus -eq 200) {
if ($json.transactionId -cne $Key -or $json.status -cne 'COMPLETED' -or -not [bool]$json.replayed) {
throw "replay response contract mismatch: $body"
}
} elseif ($json.errorCode -cne 'IDEMPOTENCY_CONFLICT') {
throw "conflict response contract mismatch: $body"
}
"DEMO_TRANSFER_OK key=$Key amount=$Amount status=$status"
STEP 06 / 13
코드 한 줄씩 한국어로 번역
비어 있지 않은 58줄을 모두 한국어로 옮깁니다.
비어 있지 않은 원본 줄은 하나도 생략하지 않습니다.
| 줄 | 원본 | 한국어 번역 |
|---|---|---|
| 1 | param( | 실행 의미: PowerShell script가 받을 입력 계약을 연다. |
| 2 | [Parameter(Mandatory=$true)][string]$Key, | 실행 의미: 이 인자가 빠지면 실행 시작 전에 binding을 거절한다. |
| 3 | [Parameter(Mandatory=$true)][long]$Amount, | 실행 의미: 이 인자가 빠지면 실행 시작 전에 binding을 거절한다. |
| 4 | [Parameter(Mandatory=$true)][ValidateSet(200, 201, 409)][int]$ExpectedStatus, | 실행 의미: 이 인자가 빠지면 실행 시작 전에 binding을 거절한다. |
| 5 | [string]$StatePath = 'evidence\w24\demo-state.json' | 실행 의미: run-transfer.ps1의 다음 검증 또는 설명 단계를 구성한다. |
| 6 | ) | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 8 | $ErrorActionPreference = 'Stop' | 실행 의미: PowerShell 오류를 계속 진행하지 않고 중단시키는 기본 정책을 둔다. |
| 9 | $user = $env:FCL_DEMO_USER | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 10 | $password = $env:FCL_DEMO_PASSWORD | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 11 | if ([string]::IsNullOrWhiteSpace($user) -or [string]::IsNullOrWhiteSpace($password)) { | 실행 의미: 조건·반복·함수의 실행 block을 연다. |
| 12 | throw 'Set FCL_DEMO_USER and FCL_DEMO_PASSWORD in this terminal only.' | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 13 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 14 | if (!(Test-Path -LiteralPath $StatePath -PathType Leaf)) { | 실행 의미: 필수 파일이나 경로가 실제로 있는지 확인한다. |
| 15 | throw "Run reset-demo.ps1 first; missing state: $StatePath" | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 16 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 17 | $state = Get-Content -LiteralPath $StatePath -Raw | ConvertFrom-Json | 실행 의미: JSON text를 필드로 접근 가능한 PowerShell object로 바꾼다. |
| 18 | if ([long]$state.fromAccountId -le 0 -or [long]$state.toAccountId -le 0) { | 실행 의미: 계좌 생성 응답의 numeric ID를 다음 transfer·대사 단계로 전달한다. |
| 19 | throw 'demo state has invalid numeric account IDs' | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 20 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 22 | $pair = [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes("${user}:${password}")) | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 23 | $headers = @{ Authorization = "Basic $pair"; 'X-Request-Id' = "w24-transfer-$Key-$Amount" } | 실행 의미: 인증 header를 runtime에서 만들되 evidence에 원문 비밀을 남기지 않는다. |
| 24 | $payload = @{ | 실행 의미: 조건·반복·함수의 실행 block을 연다. |
| 25 | transactionId = $Key | 실행 의미: run-transfer.ps1의 다음 검증 또는 설명 단계를 구성한다. |
| 26 | fromAccountId = [long]$state.fromAccountId | 실행 의미: 계좌 생성 응답의 numeric ID를 다음 transfer·대사 단계로 전달한다. |
| 27 | toAccountId = [long]$state.toAccountId | 실행 의미: 계좌 생성 응답의 numeric ID를 다음 transfer·대사 단계로 전달한다. |
| 28 | amount = $Amount | 실행 의미: run-transfer.ps1의 다음 검증 또는 설명 단계를 구성한다. |
| 29 | } | ConvertTo-Json -Compress | 실행 의미: 검증된 object를 JSON evidence text로 직렬화한다. |
| 31 | $status = 0 | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 32 | $body = '' | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 33 | try { | 실행 의미: 조건·반복·함수의 실행 block을 연다. |
| 34 | $response = Invoke-WebRequest -UseBasicParsing -Method Post -Uri "$($state.baseUrl)/api/transfers" ` | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 35 | -Headers $headers -ContentType 'application/json' -Body $payload | 실행 의미: run-transfer.ps1의 다음 검증 또는 설명 단계를 구성한다. |
| 36 | $status = [int]$response.StatusCode | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 37 | $body = [string]$response.Content | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 38 | } catch { | 실행 의미: 실패 object를 보존해 cleanup 뒤 다시 실패시키도록 잡는다. |
| 39 | $httpResponse = $_.Exception.Response | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 40 | if ($null -eq $httpResponse) { throw } | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 41 | $status = [int]$httpResponse.StatusCode | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 42 | $stream = $httpResponse.GetResponseStream() | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 43 | $reader = New-Object System.IO.StreamReader($stream) | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 44 | try { $body = $reader.ReadToEnd() } finally { $reader.Dispose(); $stream.Dispose() } | 실행 의미: 중간 실패가 있어도 반드시 실행할 cleanup 경계를 연다. |
| 45 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 47 | if ($status -ne $ExpectedStatus) { | 실행 의미: 각 demo 단계가 반드시 반환해야 할 HTTP status를 입력으로 고정한다. |
| 48 | throw "unexpected transfer status expected=$ExpectedStatus actual=$status body=$body" | 실행 의미: 각 demo 단계가 반드시 반환해야 할 HTTP status를 입력으로 고정한다. |
| 49 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 50 | $json = $body | ConvertFrom-Json | 실행 의미: JSON text를 필드로 접근 가능한 PowerShell object로 바꾼다. |
| 51 | if ($ExpectedStatus -eq 201) { | 실행 의미: 각 demo 단계가 반드시 반환해야 할 HTTP status를 입력으로 고정한다. |
| 52 | if ($json.transactionId -cne $Key -or $json.status -cne 'COMPLETED' -or [bool]$json.replayed) { | 실행 의미: 조건·반복·함수의 실행 block을 연다. |
| 53 | throw "first response contract mismatch: $body" | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 54 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 55 | } elseif ($ExpectedStatus -eq 200) { | 실행 의미: 각 demo 단계가 반드시 반환해야 할 HTTP status를 입력으로 고정한다. |
| 56 | if ($json.transactionId -cne $Key -or $json.status -cne 'COMPLETED' -or -not [bool]$json.replayed) { | 실행 의미: 조건·반복·함수의 실행 block을 연다. |
| 57 | throw "replay response contract mismatch: $body" | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 58 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 59 | } elseif ($json.errorCode -cne 'IDEMPOTENCY_CONFLICT') { | 실행 의미: 같은 actor·operation·key의 요청을 최초·replay·conflict로 구분한다. |
| 60 | throw "conflict response contract mismatch: $body" | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 61 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 62 | "DEMO_TRANSFER_OK key=$Key amount=$Amount status=$status" | 실행 의미: 한 transfer 호출이 기대 status와 일치했음을 transcript에 남긴다. |
STEP 07 / 13
기존 수준의 한 줄 읽기·문법 해부
쉬운 설명 다음에 문법과 실행 순서를 정밀하게 읽습니다.
한 줄로 읽기run-transfer.ps1 — canonical JSON과 201·200·409 계약는 state의 numeric accountId로 transfer JSON을 만들고 idempotency key·amount별 예상 HTTP status와 response를 기록한다.
문법 해부
- .ps1 문법에서 선언·조건·pipeline·block 경계를 먼저 나눈다.
- expected 값과 actual 결과를 같은 이름처럼 보여도 서로 다른 source로 읽는다.
- native exit·row count·hash·사람 판정을 서로 대체하지 않는다.
실행 순서
- 입력 경로·fixture·환경변수·expected 계약을 고정한다.
- source가 실행하는 native process·HTTP·SQL 또는 형식 검사를 따라간다.
- actual 값과 exact marker를 대조하고 실패면 성공 발행 전에 중단한다.
- finally cleanup과 비범위를 evidence에 남긴다.
W24 조각별 정밀 해설
F09-C01 · 원문 1–12줄
- 문법 해부
- .ps1 문법으로 1–12줄의 선언·조건·pipeline·block을 나눈다.
- 실제 값 추적
- 201 first, 200 replay, 409 conflict를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- expected와 actual이 일치하고 owner evidence가 같은 run/hash에 연결되는 경우다.
- 틀린 예·반례
- reset state가 없거나 ID가 잘못되면 실패한다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- 파일 존재·문자열·hash·exit0 하나를 의미 Green 전체와 같다고 보지 않는다.
- 하지 않는 일
- reset state가 없거나 ID가 잘못되면 실패한다; 비밀번호 원문을 evidence에 쓰지 않는다; DB 대사는 별도 script 책임이다
- 다음 연결
- 다음 조각 또는 F09 evidence 판정으로 상태를 넘긴다.
F09-C02 · 원문 13–24줄
- 문법 해부
- .ps1 문법으로 13–24줄의 선언·조건·pipeline·block을 나눈다.
- 실제 값 추적
- 201 first, 200 replay, 409 conflict를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- expected와 actual이 일치하고 owner evidence가 같은 run/hash에 연결되는 경우다.
- 틀린 예·반례
- reset state가 없거나 ID가 잘못되면 실패한다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- 파일 존재·문자열·hash·exit0 하나를 의미 Green 전체와 같다고 보지 않는다.
- 하지 않는 일
- reset state가 없거나 ID가 잘못되면 실패한다; 비밀번호 원문을 evidence에 쓰지 않는다; DB 대사는 별도 script 책임이다
- 다음 연결
- 다음 조각 또는 F09 evidence 판정으로 상태를 넘긴다.
F09-C03 · 원문 25–36줄
- 문법 해부
- .ps1 문법으로 25–36줄의 선언·조건·pipeline·block을 나눈다.
- 실제 값 추적
- 201 first, 200 replay, 409 conflict를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- expected와 actual이 일치하고 owner evidence가 같은 run/hash에 연결되는 경우다.
- 틀린 예·반례
- reset state가 없거나 ID가 잘못되면 실패한다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- 파일 존재·문자열·hash·exit0 하나를 의미 Green 전체와 같다고 보지 않는다.
- 하지 않는 일
- reset state가 없거나 ID가 잘못되면 실패한다; 비밀번호 원문을 evidence에 쓰지 않는다; DB 대사는 별도 script 책임이다
- 다음 연결
- 다음 조각 또는 F09 evidence 판정으로 상태를 넘긴다.
F09-C04 · 원문 37–48줄
- 문법 해부
- .ps1 문법으로 37–48줄의 선언·조건·pipeline·block을 나눈다.
- 실제 값 추적
- 201 first, 200 replay, 409 conflict를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- expected와 actual이 일치하고 owner evidence가 같은 run/hash에 연결되는 경우다.
- 틀린 예·반례
- reset state가 없거나 ID가 잘못되면 실패한다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- 파일 존재·문자열·hash·exit0 하나를 의미 Green 전체와 같다고 보지 않는다.
- 하지 않는 일
- reset state가 없거나 ID가 잘못되면 실패한다; 비밀번호 원문을 evidence에 쓰지 않는다; DB 대사는 별도 script 책임이다
- 다음 연결
- 다음 조각 또는 F09 evidence 판정으로 상태를 넘긴다.
F09-C05 · 원문 49–60줄
- 문법 해부
- .ps1 문법으로 49–60줄의 선언·조건·pipeline·block을 나눈다.
- 실제 값 추적
- 201 first, 200 replay, 409 conflict를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- expected와 actual이 일치하고 owner evidence가 같은 run/hash에 연결되는 경우다.
- 틀린 예·반례
- reset state가 없거나 ID가 잘못되면 실패한다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- 파일 존재·문자열·hash·exit0 하나를 의미 Green 전체와 같다고 보지 않는다.
- 하지 않는 일
- reset state가 없거나 ID가 잘못되면 실패한다; 비밀번호 원문을 evidence에 쓰지 않는다; DB 대사는 별도 script 책임이다
- 다음 연결
- 다음 조각 또는 F09 evidence 판정으로 상태를 넘긴다.
F09-C06 · 원문 61–62줄
- 문법 해부
- .ps1 문법으로 61–62줄의 선언·조건·pipeline·block을 나눈다.
- 실제 값 추적
- 201 first, 200 replay, 409 conflict를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- expected와 actual이 일치하고 owner evidence가 같은 run/hash에 연결되는 경우다.
- 틀린 예·반례
- reset state가 없거나 ID가 잘못되면 실패한다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- 파일 존재·문자열·hash·exit0 하나를 의미 Green 전체와 같다고 보지 않는다.
- 하지 않는 일
- reset state가 없거나 ID가 잘못되면 실패한다; 비밀번호 원문을 evidence에 쓰지 않는다; DB 대사는 별도 script 책임이다
- 다음 연결
- 다음 조각 또는 F09 evidence 판정으로 상태를 넘긴다.
실행 순서 — run-transfer.ps1 — canonical JSON과 201·200·409 계약
-
200 replay가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 state의 numeric accountId로 transfer JSON을 만들고 idempotency key·amount별 예상 HTTP status와 response를 기록한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘비밀번호 원문을 evidence에 쓰지 않는다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 200 replay와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 08 / 13
실제 값 따라가기
같은 입력값이 어느 줄을 지나 어떤 결과가 되는지 추적합니다.
| 순서 | 들어온 값 | 코드가 하는 일 | 나온 값·상태 | 경계 |
|---|---|---|---|---|
| 입력 | 201 first | source 계약에 대입 | F09 실행/설명 시작 상태 | reset state가 없거나 ID가 잘못되면 실패한다 |
| 검증 | 200 replay | expected와 actual 또는 형식 대조 | 통과 또는 첫 mismatch | 비밀번호 원문을 evidence에 쓰지 않는다 |
| 증거 | amount 1000/2000 | marker·hash·row를 같은 run에 연결 | 범위가 적힌 evidence 후보 | DB 대사는 별도 script 책임이다 |
실제 값 — run-transfer.ps1 — canonical JSON과 201·200·409 계약
-
409 conflict가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 state의 numeric accountId로 transfer JSON을 만들고 idempotency key·amount별 예상 HTTP status와 response를 기록한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘DB 대사는 별도 script 책임이다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 409 conflict와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 09 / 13
Gradle·PowerShell·HTTP·PostgreSQL 내부에서 벌어지는 일
Gradle·JUnit XML·PowerShell·HTTP·PostgreSQL·Docker에서 실제로 일어나는 일과 증명 범위를 구분합니다.
run-transfer.ps1 bytes와 expected 값을 읽는다.
파일 존재만으로 runtime 성공은 아니다.native exit·HTTP status·JUnit XML·DB row·hash 중 이 파일이 소유한 값을 만든다.
reset state가 없거나 ID가 잘못되면 실패한다관련 evidence와 사람 의미 검토를 release 후보에 연결한다.
DB 대사는 별도 script 책임이다첫 실패 경계 — run-transfer.ps1 — canonical JSON과 201·200·409 계약
-
amount 1000/2000가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 state의 numeric accountId로 transfer JSON을 만들고 idempotency key·amount별 예상 HTTP status와 response를 기록한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘reset state가 없거나 ID가 잘못되면 실패한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 amount 1000/2000와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 10 / 13
흔한 착각과 틀린 예
그럴듯하지만 틀린 해석을 반례로 고칩니다.
❌ 201 first 문자열이 source에 있으니 실제 실행도 Green이다.
왜 틀리나 source literal과 runtime 관찰값은 다른 증거다.
바르게 읽기 native exit·actual XML/HTTP/DB evidence를 별도로 확인한다.
반례 script가 실행 전 경로 오류로 멈춰도 literal은 그대로 남는다.
❌ 파일 SHA-256이 있으면 내용의 의미와 사실성도 검증됐다.
왜 틀리나 hash는 동일 bytes만 말한다.
바르게 읽기 schema·수치·질문·근거는 별도 자동 또는 사람 판정을 거친다.
반례 빈 review 질문을 가진 CSV도 안정된 hash를 가진다.
❌ LOCAL_ARTIFACT_VALIDATED는 release Green과 같다.
왜 틀리나 generic validator는 파일 shape만 확인한다.
바르게 읽기 HUMAN_SEMANTIC_REVIEW_REQUIRED를 유지한다.
반례 잘못된 track 점수표도 byte 수 조건은 통과할 수 있다.
❌ 이 파일이 W24 전체 lifecycle을 모두 소유한다.
왜 틀리나 각 source는 Gate·demo·cleanup·사람 review 중 일부만 담당한다.
바르게 읽기 owner와 non-responsibility를 release manifest에서 분리한다.
반례 D4 source audit에는 runtime_claim=false가 명시된다.
❌ 이전 주 Green이나 오래된 log를 현재 commit 결과로 재사용한다.
왜 틀리나 source·commit·actual result가 같은 실행에 묶이지 않는다.
바르게 읽기 release 후보에서 새 evidence와 hash를 만든다.
반례 expected JSON이 바뀌면 예전 XML은 exact inventory를 증명하지 못한다.
STEP 11 / 13
이 코드가 보장하지 않는 것
이 코드가 책임지지 않는 일을 분리합니다.
reset state가 없거나 ID가 잘못되면 실패한다
이 책임을 맡는 곳: runtime Gate비밀번호 원문을 evidence에 쓰지 않는다
이 책임을 맡는 곳: external/human reviewDB 대사는 별도 script 책임이다
이 책임을 맡는 곳: release manifestreset state가 없거나 ID가 잘못되면 실패한다
이 책임을 맡는 곳: 운영 환경증명하지 않는 범위 — run-transfer.ps1 — canonical JSON과 201·200·409 계약
-
201 first가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 state의 numeric accountId로 transfer JSON을 만들고 idempotency key·amount별 예상 HTTP status와 response를 기록한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘비밀번호 원문을 evidence에 쓰지 않는다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 201 first와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 12 / 13
직접 다시 써보기
뜻 → 조각 → 전체 코드 순서로 다시 씁니다.
1단계 · 뜻부터 복원
- state의 numeric accountId로 transfer JSON을 만들고 idempotency key·amount별 예상 HTTP status와 response를 기록한다.
- 핵심 값은 201 first, 200 replay, 409 conflict, amount 1000/2000다.
2단계 · 코드 조각 재조립
- 1. PowerShell script가 받을 입력 계약을 연다
- 2. 이 인자가 빠지면 실행 시작 전에 binding을 거절한다
- 3. 이 인자가 빠지면 실행 시작 전에 binding을 거절한다
- 4. 이 인자가 빠지면 실행 시작 전에 binding을 거절한다
- 5. run-transfer.ps1의 다음 검증 또는 설명 단계를 구성한다
- 6. 앞에서 연 block 또는 호출 범위를 닫는다
- 8. PowerShell 오류를 계속 진행하지 않고 중단시키는 기본 정책을 둔다
- 9. 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다
3단계 · 파일 전체 다시 쓰기
scripts/run-transfer.ps1을 새 파일에 다시 쓰고 expected·actual·실패·cleanup·비범위를 주석으로 표시한다.
자가 점검
- 비어 있지 않은 모든 source 줄을 한 번씩 읽었나?
- source shape와 runtime Green을 분리했나?
- 사람 검토·외부 상태를 자동 성공으로 꾸미지 않았나?
- 첫 실패와 cleanup 책임을 설명할 수 있나?
STEP 13 / 13
전체 원본 source
감사로 고정한 전체 source를 가감 없이 확인합니다.
원문 정본 전체 source 확인하기
param(
[Parameter(Mandatory=$true)][string]$Key,
[Parameter(Mandatory=$true)][long]$Amount,
[Parameter(Mandatory=$true)][ValidateSet(200, 201, 409)][int]$ExpectedStatus,
[string]$StatePath = 'evidence\w24\demo-state.json'
)
$ErrorActionPreference = 'Stop'
$user = $env:FCL_DEMO_USER
$password = $env:FCL_DEMO_PASSWORD
if ([string]::IsNullOrWhiteSpace($user) -or [string]::IsNullOrWhiteSpace($password)) {
throw 'Set FCL_DEMO_USER and FCL_DEMO_PASSWORD in this terminal only.'
}
if (!(Test-Path -LiteralPath $StatePath -PathType Leaf)) {
throw "Run reset-demo.ps1 first; missing state: $StatePath"
}
$state = Get-Content -LiteralPath $StatePath -Raw | ConvertFrom-Json
if ([long]$state.fromAccountId -le 0 -or [long]$state.toAccountId -le 0) {
throw 'demo state has invalid numeric account IDs'
}
$pair = [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes("${user}:${password}"))
$headers = @{ Authorization = "Basic $pair"; 'X-Request-Id' = "w24-transfer-$Key-$Amount" }
$payload = @{
transactionId = $Key
fromAccountId = [long]$state.fromAccountId
toAccountId = [long]$state.toAccountId
amount = $Amount
} | ConvertTo-Json -Compress
$status = 0
$body = ''
try {
$response = Invoke-WebRequest -UseBasicParsing -Method Post -Uri "$($state.baseUrl)/api/transfers" `
-Headers $headers -ContentType 'application/json' -Body $payload
$status = [int]$response.StatusCode
$body = [string]$response.Content
} catch {
$httpResponse = $_.Exception.Response
if ($null -eq $httpResponse) { throw }
$status = [int]$httpResponse.StatusCode
$stream = $httpResponse.GetResponseStream()
$reader = New-Object System.IO.StreamReader($stream)
try { $body = $reader.ReadToEnd() } finally { $reader.Dispose(); $stream.Dispose() }
}
if ($status -ne $ExpectedStatus) {
throw "unexpected transfer status expected=$ExpectedStatus actual=$status body=$body"
}
$json = $body | ConvertFrom-Json
if ($ExpectedStatus -eq 201) {
if ($json.transactionId -cne $Key -or $json.status -cne 'COMPLETED' -or [bool]$json.replayed) {
throw "first response contract mismatch: $body"
}
} elseif ($ExpectedStatus -eq 200) {
if ($json.transactionId -cne $Key -or $json.status -cne 'COMPLETED' -or -not [bool]$json.replayed) {
throw "replay response contract mismatch: $body"
}
} elseif ($json.errorCode -cne 'IDEMPOTENCY_CONFLICT') {
throw "conflict response contract mismatch: $body"
}
"DEMO_TRANSFER_OK key=$Key amount=$Amount status=$status"
10reconcile-demo.ps1 — account와 ledger 합계 mismatch 0 검증
scripts/reconcile-demo.ps1
PDF 전문 정본 · packaged PowerShell source · 정본 · W24-F1029줄 연결29줄 번역3 chunks
reconcile-demo.ps1 — account와 ledger 합계 mismatch 0 검증
scripts/reconcile-demo.ps1
PDF 전문 정본 · packaged PowerShell source · 정본 · W24-F10STEP 01 / 13
오늘 이 코드에서 해결할 문제
무엇을 이해해야 하는지 질문부터 잡습니다.
demo의 두 accountId를 대상으로 account.balance와 ledger_entry 합계를 비교해 mismatch가 정확히 0인지 확인한다.
- mismatches=0은 어느 source와 실제 결과에서 확인해야 할까?
- 첫 실패를 만드는 조건과 fail-closed 지점은 어디일까?
- 왜 ‘두 demo 계좌만 검증한다’를 별도 경계로 남겨야 할까?
mismatches=0V001 accountledger_entryDEMO_RECONCILIATION_GREEN왜 필요한가 — reconcile-demo.ps1 — account와 ledger 합계 mismatch 0 검증
-
mismatches=0가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 demo의 두 accountId를 대상으로 account.balance와 ledger_entry 합계를 비교해 mismatch가 정확히 0인지 확인한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘두 demo 계좌만 검증한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 mismatches=0와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 02 / 13
아주 짧게: 이 코드는 왜 필요할까?
웹소설 대신 이 코드가 필요한 이유만 두 문단으로 쉽게 봅니다.
새 기능을 멈춘 팀이 코드·test·문서·demo를 같은 release 후보에 묶어 하나씩 검수한다.
검수 도장이 붙은 공통 거래 코어 출고 상자
이 파일은 demo의 두 accountId를 대상으로 account.balance와 ledger_entry 합계를 비교해 mismatch가 정확히 0인지 확인한다. 눈으로 읽을 때는 각 줄을 검수표 한 칸처럼 보고, 입력과 다음 상태를 놓치지 않는다.
마지막 도장은 source shape와 실제 runtime·사람 검토를 구분한 뒤에만 찍는다. 특히 두 demo 계좌만 검증한다
딱 여기까지만 비유는 실행 순서를 돕지만 실제 Gradle·Docker·DB·사람 review를 대신하지 않는다.
STEP 03 / 13
초등학생도 이해하는 설명
생활 비유와 실제 코드의 경계를 함께 확인합니다.
값 1: mismatches=0
이 파일에서 계속 확인할 고정 단서가 mismatches=0다.
- 코드 연결
F10 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- 두 demo 계좌만 검증한다
값 2: V001 account
이 파일에서 계속 확인할 고정 단서가 V001 account다.
- 코드 연결
F10 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- 컨테이너·DB가 실제 실행 중이어야 한다
값 3: ledger_entry
이 파일에서 계속 확인할 고정 단서가 ledger_entry다.
- 코드 연결
F10 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- 운영 전사 대사를 증명하지 않는다
값 4: DEMO_RECONCILIATION_GREEN
이 파일에서 계속 확인할 고정 단서가 DEMO_RECONCILIATION_GREEN다.
- 코드 연결
F10 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- 두 demo 계좌만 검증한다
STEP 04 / 13
비유 ↔ 코드 전체 연결표
감사 규칙상 연결 대상인 원본 29줄을 빠짐없이 연결합니다.
| 줄 | 정확한 원본 줄 | STARRY 비유 | 실제 뜻·입력·결과·한계 |
|---|---|---|---|
| 1줄F10-L01 | param( |
출고표 1번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 PowerShell script가 받을 입력 계약을 연다.
|
| 2줄F10-L02 | [ |
출고표 2번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 reconcile-demo.ps1의 다음 검증 또는 설명 단계를 구성한다.
|
| 3줄F10-L03 | [ |
출고표 3번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 이 인자가 빠지면 실행 시작 전에 binding을 거절한다.
|
| 4줄F10-L04 | ) |
출고표 4번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 6줄F10-L06 | $ErrorActionPreference = |
출고표 6번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 PowerShell 오류를 계속 진행하지 않고 중단시키는 기본 정책을 둔다.
|
| 7줄F10-L07 | if ( |
출고표 7번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 필수 파일이나 경로가 실제로 있는지 확인한다.
|
| 8줄F10-L08 | throw "Run reset-demo. |
출고표 8번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 9줄F10-L09 | } |
출고표 9번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 10줄F10-L10 | $state = |
출고표 10번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 JSON text를 필드로 접근 가능한 PowerShell object로 바꾼다.
|
| 11줄F10-L11 | $fromId = |
출고표 11번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계좌 생성 응답의 numeric ID를 다음 transfer·대사 단계로 전달한다.
|
| 12줄F10-L12 | $toId = |
출고표 12번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계좌 생성 응답의 numeric ID를 다음 transfer·대사 단계로 전달한다.
|
| 13줄F10-L13 | if ( |
출고표 13번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 15줄F10-L15 | $sql = |
출고표 15번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 16줄F10-L16 | SELECT COUNT( |
출고표 16번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 SQL 집합의 입력·변환·필터 단계를 선언한다.
|
| 17줄F10-L17 | FROM ( |
출고표 17번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 SQL 집합의 입력·변환·필터 단계를 선언한다.
|
| 18줄F10-L18 | SELECT a. |
출고표 18번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 SQL 집합의 입력·변환·필터 단계를 선언한다.
|
| 19줄F10-L19 | FROM account a |
출고표 19번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 SQL 집합의 입력·변환·필터 단계를 선언한다.
|
| 20줄F10-L20 | LEFT JOIN ledger_entry l ON l. |
출고표 20번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 reconcile-demo.ps1의 다음 검증 또는 설명 단계를 구성한다.
|
| 21줄F10-L21 | WHERE a. |
출고표 21번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 SQL 집합의 입력·변환·필터 단계를 선언한다.
|
| 22줄F10-L22 | GROUP BY a. |
출고표 22번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 reconcile-demo.ps1의 다음 검증 또는 설명 단계를 구성한다.
|
| 23줄F10-L23 | HAVING a. |
출고표 23번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 reconcile-demo.ps1의 다음 검증 또는 설명 단계를 구성한다.
|
| 24줄F10-L24 | ) mismatch; |
출고표 24번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 reconcile-demo.ps1의 다음 검증 또는 설명 단계를 구성한다.
|
| 25줄F10-L25 | "@ |
출고표 25번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 reconcile-demo.ps1의 다음 검증 또는 설명 단계를 구성한다.
|
| 26줄F10-L26 | $raw = |
출고표 26번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 Markdown 표 또는 PowerShell pipeline에서 값을 열이나 다음 명령으로 연결한다.
|
| 27줄F10-L27 | $exitCode = |
출고표 27번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 native process 종료 코드를 검사해 실패를 놓치지 않는다.
|
| 28줄F10-L28 | if ( |
출고표 28번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 account balance와 ledger 합계를 비교해 mismatch를 찾는다.
|
| 29줄F10-L29 | $value = |
출고표 29번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 고정 목록의 각 항목에 같은 검사를 반복 적용한다.
|
| 30줄F10-L30 | if ( |
출고표 30번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 account balance와 ledger 합계를 비교해 mismatch를 찾는다.
|
| 31줄F10-L31 | 'DEMO_RECONCILIATION_GREEN mismatches= |
출고표 31번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 account balance와 ledger 합계를 비교해 mismatch를 찾는다.
|
STEP 05 / 13
원본 코드 조각
원본을 3개 의미 조각으로 나누어 그대로 확인합니다.
파일을 한꺼번에 외우지 않고 실행 의미가 이어지는 작은 조각으로 봅니다. 아래 코드는 hash로 고정한 native 정본 source에서 그대로 잘랐습니다.
param(
[string]$StatePath = 'evidence\w24\demo-state.json',
[Parameter(Mandatory=$true)][string]$Container
)
$ErrorActionPreference = 'Stop'
if (!(Test-Path -LiteralPath $StatePath -PathType Leaf)) {
throw "Run reset-demo.ps1 first; missing state: $StatePath"
}
$state = Get-Content -LiteralPath $StatePath -Raw | ConvertFrom-Json
$fromId = [long]$state.fromAccountId
$toId = [long]$state.toAccountId
if ($fromId -le 0 -or $toId -le 0) { throw 'demo state has invalid account IDs' }
$sql = @"
SELECT COUNT(*)
FROM (
SELECT a.id
FROM account a
LEFT JOIN ledger_entry l ON l.account_id = a.id
WHERE a.id IN ($fromId, $toId)
GROUP BY a.id, a.balance
HAVING a.balance <> COALESCE(SUM(l.signed_amount), 0)
) mismatch;
"@
$raw = @($sql | docker exec -i $Container psql -X -qAt -v ON_ERROR_STOP=1 -U app -d financial_core 2>&1)
$exitCode = $LASTEXITCODE
if ($exitCode -ne 0) { throw "reconciliation query failed: $($raw -join "`n")" }
$value = (@($raw | ForEach-Object { [string]$_ }) -join '').Trim()
if ($value -cne '0') { throw "reconciliation mismatch count=$value" }
'DEMO_RECONCILIATION_GREEN mismatches=0'
STEP 06 / 13
코드 한 줄씩 한국어로 번역
비어 있지 않은 29줄을 모두 한국어로 옮깁니다.
비어 있지 않은 원본 줄은 하나도 생략하지 않습니다.
| 줄 | 원본 | 한국어 번역 |
|---|---|---|
| 1 | param( | 실행 의미: PowerShell script가 받을 입력 계약을 연다. |
| 2 | [string]$StatePath = 'evidence\w24\demo-state.json', | 실행 의미: reconcile-demo.ps1의 다음 검증 또는 설명 단계를 구성한다. |
| 3 | [Parameter(Mandatory=$true)][string]$Container | 실행 의미: 이 인자가 빠지면 실행 시작 전에 binding을 거절한다. |
| 4 | ) | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 6 | $ErrorActionPreference = 'Stop' | 실행 의미: PowerShell 오류를 계속 진행하지 않고 중단시키는 기본 정책을 둔다. |
| 7 | if (!(Test-Path -LiteralPath $StatePath -PathType Leaf)) { | 실행 의미: 필수 파일이나 경로가 실제로 있는지 확인한다. |
| 8 | throw "Run reset-demo.ps1 first; missing state: $StatePath" | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 9 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 10 | $state = Get-Content -LiteralPath $StatePath -Raw | ConvertFrom-Json | 실행 의미: JSON text를 필드로 접근 가능한 PowerShell object로 바꾼다. |
| 11 | $fromId = [long]$state.fromAccountId | 실행 의미: 계좌 생성 응답의 numeric ID를 다음 transfer·대사 단계로 전달한다. |
| 12 | $toId = [long]$state.toAccountId | 실행 의미: 계좌 생성 응답의 numeric ID를 다음 transfer·대사 단계로 전달한다. |
| 13 | if ($fromId -le 0 -or $toId -le 0) { throw 'demo state has invalid account IDs' } | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 15 | $sql = @" | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 16 | SELECT COUNT(*) | 실행 의미: SQL 집합의 입력·변환·필터 단계를 선언한다. |
| 17 | FROM ( | 실행 의미: SQL 집합의 입력·변환·필터 단계를 선언한다. |
| 18 | SELECT a.id | 실행 의미: SQL 집합의 입력·변환·필터 단계를 선언한다. |
| 19 | FROM account a | 실행 의미: SQL 집합의 입력·변환·필터 단계를 선언한다. |
| 20 | LEFT JOIN ledger_entry l ON l.account_id = a.id | 실행 의미: reconcile-demo.ps1의 다음 검증 또는 설명 단계를 구성한다. |
| 21 | WHERE a.id IN ($fromId, $toId) | 실행 의미: SQL 집합의 입력·변환·필터 단계를 선언한다. |
| 22 | GROUP BY a.id, a.balance | 실행 의미: reconcile-demo.ps1의 다음 검증 또는 설명 단계를 구성한다. |
| 23 | HAVING a.balance <> COALESCE(SUM(l.signed_amount), 0) | 실행 의미: reconcile-demo.ps1의 다음 검증 또는 설명 단계를 구성한다. |
| 24 | ) mismatch; | 실행 의미: reconcile-demo.ps1의 다음 검증 또는 설명 단계를 구성한다. |
| 25 | "@ | 실행 의미: reconcile-demo.ps1의 다음 검증 또는 설명 단계를 구성한다. |
| 26 | $raw = @($sql | docker exec -i $Container psql -X -qAt -v ON_ERROR_STOP=1 -U app -d financial_core 2>&1) | 실행 의미: Markdown 표 또는 PowerShell pipeline에서 값을 열이나 다음 명령으로 연결한다. |
| 27 | $exitCode = $LASTEXITCODE | 실행 의미: native process 종료 코드를 검사해 실패를 놓치지 않는다. |
| 28 | if ($exitCode -ne 0) { throw "reconciliation query failed: $($raw -join "`n")" } | 실행 의미: account balance와 ledger 합계를 비교해 mismatch를 찾는다. |
| 29 | $value = (@($raw | ForEach-Object { [string]$_ }) -join '').Trim() | 실행 의미: 고정 목록의 각 항목에 같은 검사를 반복 적용한다. |
| 30 | if ($value -cne '0') { throw "reconciliation mismatch count=$value" } | 실행 의미: account balance와 ledger 합계를 비교해 mismatch를 찾는다. |
| 31 | 'DEMO_RECONCILIATION_GREEN mismatches=0' | 실행 의미: account balance와 ledger 합계를 비교해 mismatch를 찾는다. |
STEP 07 / 13
기존 수준의 한 줄 읽기·문법 해부
쉬운 설명 다음에 문법과 실행 순서를 정밀하게 읽습니다.
한 줄로 읽기reconcile-demo.ps1 — account와 ledger 합계 mismatch 0 검증는 demo의 두 accountId를 대상으로 account.balance와 ledger_entry 합계를 비교해 mismatch가 정확히 0인지 확인한다.
문법 해부
- .ps1 문법에서 선언·조건·pipeline·block 경계를 먼저 나눈다.
- expected 값과 actual 결과를 같은 이름처럼 보여도 서로 다른 source로 읽는다.
- native exit·row count·hash·사람 판정을 서로 대체하지 않는다.
실행 순서
- 입력 경로·fixture·환경변수·expected 계약을 고정한다.
- source가 실행하는 native process·HTTP·SQL 또는 형식 검사를 따라간다.
- actual 값과 exact marker를 대조하고 실패면 성공 발행 전에 중단한다.
- finally cleanup과 비범위를 evidence에 남긴다.
W24 조각별 정밀 해설
F10-C01 · 원문 1–12줄
- 문법 해부
- .ps1 문법으로 1–12줄의 선언·조건·pipeline·block을 나눈다.
- 실제 값 추적
- mismatches=0, V001 account, ledger_entry를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- expected와 actual이 일치하고 owner evidence가 같은 run/hash에 연결되는 경우다.
- 틀린 예·반례
- 두 demo 계좌만 검증한다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- 파일 존재·문자열·hash·exit0 하나를 의미 Green 전체와 같다고 보지 않는다.
- 하지 않는 일
- 두 demo 계좌만 검증한다; 컨테이너·DB가 실제 실행 중이어야 한다; 운영 전사 대사를 증명하지 않는다
- 다음 연결
- 다음 조각 또는 F10 evidence 판정으로 상태를 넘긴다.
F10-C02 · 원문 13–24줄
- 문법 해부
- .ps1 문법으로 13–24줄의 선언·조건·pipeline·block을 나눈다.
- 실제 값 추적
- mismatches=0, V001 account, ledger_entry를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- expected와 actual이 일치하고 owner evidence가 같은 run/hash에 연결되는 경우다.
- 틀린 예·반례
- 두 demo 계좌만 검증한다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- 파일 존재·문자열·hash·exit0 하나를 의미 Green 전체와 같다고 보지 않는다.
- 하지 않는 일
- 두 demo 계좌만 검증한다; 컨테이너·DB가 실제 실행 중이어야 한다; 운영 전사 대사를 증명하지 않는다
- 다음 연결
- 다음 조각 또는 F10 evidence 판정으로 상태를 넘긴다.
F10-C03 · 원문 25–31줄
- 문법 해부
- .ps1 문법으로 25–31줄의 선언·조건·pipeline·block을 나눈다.
- 실제 값 추적
- mismatches=0, V001 account, ledger_entry를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- expected와 actual이 일치하고 owner evidence가 같은 run/hash에 연결되는 경우다.
- 틀린 예·반례
- 두 demo 계좌만 검증한다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- 파일 존재·문자열·hash·exit0 하나를 의미 Green 전체와 같다고 보지 않는다.
- 하지 않는 일
- 두 demo 계좌만 검증한다; 컨테이너·DB가 실제 실행 중이어야 한다; 운영 전사 대사를 증명하지 않는다
- 다음 연결
- 다음 조각 또는 F10 evidence 판정으로 상태를 넘긴다.
실행 순서 — reconcile-demo.ps1 — account와 ledger 합계 mismatch 0 검증
-
V001 account가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 demo의 두 accountId를 대상으로 account.balance와 ledger_entry 합계를 비교해 mismatch가 정확히 0인지 확인한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘컨테이너·DB가 실제 실행 중이어야 한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 V001 account와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 08 / 13
실제 값 따라가기
같은 입력값이 어느 줄을 지나 어떤 결과가 되는지 추적합니다.
| 순서 | 들어온 값 | 코드가 하는 일 | 나온 값·상태 | 경계 |
|---|---|---|---|---|
| 입력 | mismatches=0 | source 계약에 대입 | F10 실행/설명 시작 상태 | 두 demo 계좌만 검증한다 |
| 검증 | V001 account | expected와 actual 또는 형식 대조 | 통과 또는 첫 mismatch | 컨테이너·DB가 실제 실행 중이어야 한다 |
| 증거 | DEMO_RECONCILIATION_GREEN | marker·hash·row를 같은 run에 연결 | 범위가 적힌 evidence 후보 | 운영 전사 대사를 증명하지 않는다 |
실제 값 — reconcile-demo.ps1 — account와 ledger 합계 mismatch 0 검증
-
ledger_entry가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 demo의 두 accountId를 대상으로 account.balance와 ledger_entry 합계를 비교해 mismatch가 정확히 0인지 확인한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘운영 전사 대사를 증명하지 않는다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 ledger_entry와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 09 / 13
Gradle·PowerShell·HTTP·PostgreSQL 내부에서 벌어지는 일
Gradle·JUnit XML·PowerShell·HTTP·PostgreSQL·Docker에서 실제로 일어나는 일과 증명 범위를 구분합니다.
reconcile-demo.ps1 bytes와 expected 값을 읽는다.
파일 존재만으로 runtime 성공은 아니다.native exit·HTTP status·JUnit XML·DB row·hash 중 이 파일이 소유한 값을 만든다.
두 demo 계좌만 검증한다관련 evidence와 사람 의미 검토를 release 후보에 연결한다.
운영 전사 대사를 증명하지 않는다첫 실패 경계 — reconcile-demo.ps1 — account와 ledger 합계 mismatch 0 검증
-
DEMO_RECONCILIATION_GREEN가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 demo의 두 accountId를 대상으로 account.balance와 ledger_entry 합계를 비교해 mismatch가 정확히 0인지 확인한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘두 demo 계좌만 검증한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 DEMO_RECONCILIATION_GREEN와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 10 / 13
흔한 착각과 틀린 예
그럴듯하지만 틀린 해석을 반례로 고칩니다.
❌ mismatches=0 문자열이 source에 있으니 실제 실행도 Green이다.
왜 틀리나 source literal과 runtime 관찰값은 다른 증거다.
바르게 읽기 native exit·actual XML/HTTP/DB evidence를 별도로 확인한다.
반례 script가 실행 전 경로 오류로 멈춰도 literal은 그대로 남는다.
❌ 파일 SHA-256이 있으면 내용의 의미와 사실성도 검증됐다.
왜 틀리나 hash는 동일 bytes만 말한다.
바르게 읽기 schema·수치·질문·근거는 별도 자동 또는 사람 판정을 거친다.
반례 빈 review 질문을 가진 CSV도 안정된 hash를 가진다.
❌ LOCAL_ARTIFACT_VALIDATED는 release Green과 같다.
왜 틀리나 generic validator는 파일 shape만 확인한다.
바르게 읽기 HUMAN_SEMANTIC_REVIEW_REQUIRED를 유지한다.
반례 잘못된 track 점수표도 byte 수 조건은 통과할 수 있다.
❌ 이 파일이 W24 전체 lifecycle을 모두 소유한다.
왜 틀리나 각 source는 Gate·demo·cleanup·사람 review 중 일부만 담당한다.
바르게 읽기 owner와 non-responsibility를 release manifest에서 분리한다.
반례 D4 source audit에는 runtime_claim=false가 명시된다.
❌ 이전 주 Green이나 오래된 log를 현재 commit 결과로 재사용한다.
왜 틀리나 source·commit·actual result가 같은 실행에 묶이지 않는다.
바르게 읽기 release 후보에서 새 evidence와 hash를 만든다.
반례 expected JSON이 바뀌면 예전 XML은 exact inventory를 증명하지 못한다.
STEP 11 / 13
이 코드가 보장하지 않는 것
이 코드가 책임지지 않는 일을 분리합니다.
두 demo 계좌만 검증한다
이 책임을 맡는 곳: runtime Gate컨테이너·DB가 실제 실행 중이어야 한다
이 책임을 맡는 곳: external/human review운영 전사 대사를 증명하지 않는다
이 책임을 맡는 곳: release manifest두 demo 계좌만 검증한다
이 책임을 맡는 곳: 운영 환경증명하지 않는 범위 — reconcile-demo.ps1 — account와 ledger 합계 mismatch 0 검증
-
mismatches=0가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 demo의 두 accountId를 대상으로 account.balance와 ledger_entry 합계를 비교해 mismatch가 정확히 0인지 확인한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘컨테이너·DB가 실제 실행 중이어야 한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 mismatches=0와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 12 / 13
직접 다시 써보기
뜻 → 조각 → 전체 코드 순서로 다시 씁니다.
1단계 · 뜻부터 복원
- demo의 두 accountId를 대상으로 account.balance와 ledger_entry 합계를 비교해 mismatch가 정확히 0인지 확인한다.
- 핵심 값은 mismatches=0, V001 account, ledger_entry, DEMO_RECONCILIATION_GREEN다.
2단계 · 코드 조각 재조립
- 1. PowerShell script가 받을 입력 계약을 연다
- 2. reconcile-demo.ps1의 다음 검증 또는 설명 단계를 구성한다
- 3. 이 인자가 빠지면 실행 시작 전에 binding을 거절한다
- 4. 앞에서 연 block 또는 호출 범위를 닫는다
- 6. PowerShell 오류를 계속 진행하지 않고 중단시키는 기본 정책을 둔다
- 7. 필수 파일이나 경로가 실제로 있는지 확인한다
- 8. 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다
- 9. 앞에서 연 block 또는 호출 범위를 닫는다
3단계 · 파일 전체 다시 쓰기
scripts/reconcile-demo.ps1을 새 파일에 다시 쓰고 expected·actual·실패·cleanup·비범위를 주석으로 표시한다.
자가 점검
- 비어 있지 않은 모든 source 줄을 한 번씩 읽었나?
- source shape와 runtime Green을 분리했나?
- 사람 검토·외부 상태를 자동 성공으로 꾸미지 않았나?
- 첫 실패와 cleanup 책임을 설명할 수 있나?
STEP 13 / 13
전체 원본 source
감사로 고정한 전체 source를 가감 없이 확인합니다.
원문 정본 전체 source 확인하기
param(
[string]$StatePath = 'evidence\w24\demo-state.json',
[Parameter(Mandatory=$true)][string]$Container
)
$ErrorActionPreference = 'Stop'
if (!(Test-Path -LiteralPath $StatePath -PathType Leaf)) {
throw "Run reset-demo.ps1 first; missing state: $StatePath"
}
$state = Get-Content -LiteralPath $StatePath -Raw | ConvertFrom-Json
$fromId = [long]$state.fromAccountId
$toId = [long]$state.toAccountId
if ($fromId -le 0 -or $toId -le 0) { throw 'demo state has invalid account IDs' }
$sql = @"
SELECT COUNT(*)
FROM (
SELECT a.id
FROM account a
LEFT JOIN ledger_entry l ON l.account_id = a.id
WHERE a.id IN ($fromId, $toId)
GROUP BY a.id, a.balance
HAVING a.balance <> COALESCE(SUM(l.signed_amount), 0)
) mismatch;
"@
$raw = @($sql | docker exec -i $Container psql -X -qAt -v ON_ERROR_STOP=1 -U app -d financial_core 2>&1)
$exitCode = $LASTEXITCODE
if ($exitCode -ne 0) { throw "reconciliation query failed: $($raw -join "`n")" }
$value = (@($raw | ForEach-Object { [string]$_ }) -join '').Trim()
if ($value -cne '0') { throw "reconciliation mismatch count=$value" }
'DEMO_RECONCILIATION_GREEN mismatches=0'
11run-w24-demo.ps1 — reset→201→200→409→대사0 orchestration
scripts/run-w24-demo.ps1
PDF 전문 정본 · packaged PowerShell source · 정본 · W24-F1150줄 연결50줄 번역5 chunks
run-w24-demo.ps1 — reset→201→200→409→대사0 orchestration
scripts/run-w24-demo.ps1
PDF 전문 정본 · packaged PowerShell source · 정본 · W24-F11STEP 01 / 13
오늘 이 코드에서 해결할 문제
무엇을 이해해야 하는지 질문부터 잡습니다.
네 packaged script를 같은 runId·state·transcript로 묶고 모든 exact marker가 있을 때만 W24_DEMO_GREEN을 발행한다.
- first=201은 어느 source와 실제 결과에서 확인해야 할까?
- 첫 실패를 만드는 조건과 fail-closed 지점은 어디일까?
- 왜 ‘앱/DB lifecycle은 D7이 소유한다’를 별도 경계로 남겨야 할까?
first=201replay=200conflict=409mismatches=0same runId왜 필요한가 — run-w24-demo.ps1 — reset→201→200→409→대사0 orchestration
-
first=201가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 네 packaged script를 같은 runId·state·transcript로 묶고 모든 exact marker가 있을 때만 W24_DEMO_GREEN을 발행한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘앱/DB lifecycle은 D7이 소유한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 first=201와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 02 / 13
아주 짧게: 이 코드는 왜 필요할까?
웹소설 대신 이 코드가 필요한 이유만 두 문단으로 쉽게 봅니다.
새 기능을 멈춘 팀이 코드·test·문서·demo를 같은 release 후보에 묶어 하나씩 검수한다.
검수 도장이 붙은 공통 거래 코어 출고 상자
이 파일은 네 packaged script를 같은 runId·state·transcript로 묶고 모든 exact marker가 있을 때만 W24_DEMO_GREEN을 발행한다. 눈으로 읽을 때는 각 줄을 검수표 한 칸처럼 보고, 입력과 다음 상태를 놓치지 않는다.
마지막 도장은 source shape와 실제 runtime·사람 검토를 구분한 뒤에만 찍는다. 특히 앱/DB lifecycle은 D7이 소유한다
딱 여기까지만 비유는 실행 순서를 돕지만 실제 Gradle·Docker·DB·사람 review를 대신하지 않는다.
STEP 03 / 13
초등학생도 이해하는 설명
생활 비유와 실제 코드의 경계를 함께 확인합니다.
값 1: first=201
이 파일에서 계속 확인할 고정 단서가 first=201다.
- 코드 연결
F11 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- 앱/DB lifecycle은 D7이 소유한다
값 2: replay=200
이 파일에서 계속 확인할 고정 단서가 replay=200다.
- 코드 연결
F11 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- marker 하나라도 없으면 실패한다
값 3: conflict=409
이 파일에서 계속 확인할 고정 단서가 conflict=409다.
- 코드 연결
F11 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- source audit만으로 runtime Green이 아니다
값 4: mismatches=0
이 파일에서 계속 확인할 고정 단서가 mismatches=0다.
- 코드 연결
F11 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- 앱/DB lifecycle은 D7이 소유한다
값 5: same runId
이 파일에서 계속 확인할 고정 단서가 same runId다.
- 코드 연결
F11 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- marker 하나라도 없으면 실패한다
STEP 04 / 13
비유 ↔ 코드 전체 연결표
감사 규칙상 연결 대상인 원본 50줄을 빠짐없이 연결합니다.
| 줄 | 정확한 원본 줄 | STARRY 비유 | 실제 뜻·입력·결과·한계 |
|---|---|---|---|
| 1줄F11-L01 | param( |
출고표 1번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 PowerShell script가 받을 입력 계약을 연다.
|
| 2줄F11-L02 | [ |
출고표 2번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 run-w24-demo.ps1의 다음 검증 또는 설명 단계를 구성한다.
|
| 3줄F11-L03 | [ |
출고표 3번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 run-w24-demo.ps1의 다음 검증 또는 설명 단계를 구성한다.
|
| 4줄F11-L04 | [ |
출고표 4번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 run-w24-demo.ps1의 다음 검증 또는 설명 단계를 구성한다.
|
| 5줄F11-L05 | [ |
출고표 5번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 이 인자가 빠지면 실행 시작 전에 binding을 거절한다.
|
| 6줄F11-L06 | ) |
출고표 6번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 8줄F11-L08 | $ErrorActionPreference = |
출고표 8번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 PowerShell 오류를 계속 진행하지 않고 중단시키는 기본 정책을 둔다.
|
| 9줄F11-L09 | $project = |
출고표 9번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 10줄F11-L10 | Push-Location $project |
출고표 10번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 run-w24-demo.ps1의 다음 검증 또는 설명 단계를 구성한다.
|
| 11줄F11-L11 | try { |
출고표 11번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 조건·반복·함수의 실행 block을 연다.
|
| 12줄F11-L12 | $EvidencePath = |
출고표 12번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 13줄F11-L13 | $parent = |
출고표 13번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 14줄F11-L14 | if ( |
출고표 14번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 조건·반복·함수의 실행 block을 연다.
|
| 15줄F11-L15 | New-Item -ItemType Directory -Force -Path $parent | Out-Null |
출고표 15번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 Markdown 표 또는 PowerShell pipeline에서 값을 열이나 다음 명령으로 연결한다.
|
| 16줄F11-L16 | } |
출고표 16번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 17줄F11-L17 | Set-Content -LiteralPath $EvidencePath -Value "W24_DEMO_START runId= |
출고표 17번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 run-w24-demo.ps1의 다음 검증 또는 설명 단계를 구성한다.
|
| 19줄F11-L19 | function Invoke-DemoStep( |
출고표 19번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 조건·반복·함수의 실행 block을 연다.
|
| 20줄F11-L20 | $raw = |
출고표 20번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 21줄F11-L21 | $exitCode = |
출고표 21번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 native process 종료 코드를 검사해 실패를 놓치지 않는다.
|
| 22줄F11-L22 | $raw | Add-Content -LiteralPath $EvidencePath -Encoding utf8 |
출고표 22번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 Markdown 표 또는 PowerShell pipeline에서 값을 열이나 다음 명령으로 연결한다.
|
| 23줄F11-L23 | if ( |
출고표 23번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 조건·반복·함수의 실행 block을 연다.
|
| 24줄F11-L24 | throw "$Script failed exit= |
출고표 24번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 25줄F11-L25 | } |
출고표 25번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 26줄F11-L26 | return @( |
출고표 26번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 고정 목록의 각 항목에 같은 검사를 반복 적용한다.
|
| 27줄F11-L27 | } |
출고표 27번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 29줄F11-L29 | $state = |
출고표 29번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 30줄F11-L30 | $key = |
출고표 30번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 31줄F11-L31 | $resetArguments = |
출고표 31번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 32줄F11-L32 | if ( |
출고표 32번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 run-w24-demo.ps1의 다음 검증 또는 설명 단계를 구성한다.
|
| 33줄F11-L33 | Invoke-DemoStep '. |
출고표 33번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 Markdown 표 또는 PowerShell pipeline에서 값을 열이나 다음 명령으로 연결한다.
|
| 34줄F11-L34 | Invoke-DemoStep '. |
출고표 34번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 각 demo 단계가 반드시 반환해야 할 HTTP status를 입력으로 고정한다.
|
| 35줄F11-L35 | Invoke-DemoStep '. |
출고표 35번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 각 demo 단계가 반드시 반환해야 할 HTTP status를 입력으로 고정한다.
|
| 36줄F11-L36 | Invoke-DemoStep '. |
출고표 36번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 각 demo 단계가 반드시 반환해야 할 HTTP status를 입력으로 고정한다.
|
| 37줄F11-L37 | Invoke-DemoStep '. |
출고표 37번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 Markdown 표 또는 PowerShell pipeline에서 값을 열이나 다음 명령으로 연결한다.
|
| 39줄F11-L39 | $text = |
출고표 39번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 40줄F11-L40 | foreach ( |
출고표 40번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 고정 목록의 각 항목에 같은 검사를 반복 적용한다.
|
| 41줄F11-L41 | 'DEMO_RESET_OK', |
출고표 41번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 두 numeric account ID가 state에 저장된 reset 완료 marker를 낸다.
|
| 42줄F11-L42 | "DEMO_TRANSFER_OK key= |
출고표 42번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 한 transfer 호출이 기대 status와 일치했음을 transcript에 남긴다.
|
| 43줄F11-L43 | "DEMO_TRANSFER_OK key= |
출고표 43번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 한 transfer 호출이 기대 status와 일치했음을 transcript에 남긴다.
|
| 44줄F11-L44 | "DEMO_TRANSFER_OK key= |
출고표 44번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 한 transfer 호출이 기대 status와 일치했음을 transcript에 남긴다.
|
| 45줄F11-L45 | 'DEMO_RECONCILIATION_GREEN mismatches= |
출고표 45번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 account balance와 ledger 합계를 비교해 mismatch를 찾는다.
|
| 46줄F11-L46 | )) { |
출고표 46번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 조건·반복·함수의 실행 block을 연다.
|
| 47줄F11-L47 | if ( |
출고표 47번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 48줄F11-L48 | } |
출고표 48번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 49줄F11-L49 | $summary = |
출고표 49번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 201→200→409→대사0 exact marker가 모두 있을 때 demo 범위를 닫는다.
|
| 50줄F11-L50 | $summary | Add-Content -LiteralPath $EvidencePath -Encoding utf8 |
출고표 50번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 Markdown 표 또는 PowerShell pipeline에서 값을 열이나 다음 명령으로 연결한다.
|
| 51줄F11-L51 | $summary |
출고표 51번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 run-w24-demo.ps1의 다음 검증 또는 설명 단계를 구성한다.
|
| 52줄F11-L52 | } finally { |
출고표 52번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 중간 실패가 있어도 반드시 실행할 cleanup 경계를 연다.
|
| 53줄F11-L53 | Pop-Location |
출고표 53번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 run-w24-demo.ps1의 다음 검증 또는 설명 단계를 구성한다.
|
| 54줄F11-L54 | } |
출고표 54번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
STEP 05 / 13
원본 코드 조각
원본을 5개 의미 조각으로 나누어 그대로 확인합니다.
파일을 한꺼번에 외우지 않고 실행 의미가 이어지는 작은 조각으로 봅니다. 아래 코드는 hash로 고정한 native 정본 source에서 그대로 잘랐습니다.
param(
[string]$RunId = "w24-$([DateTimeOffset]::UtcNow.ToUnixTimeMilliseconds())",
[string]$EvidencePath = 'evidence\w24\demo-run.txt',
[string]$BaseUrl = '',
[Parameter(Mandatory=$true)][string]$Container
)
$ErrorActionPreference = 'Stop'
$project = Split-Path -Parent $PSScriptRoot
Push-Location $project
try {
$EvidencePath = [IO.Path]::GetFullPath($EvidencePath)
$parent = Split-Path -Parent $EvidencePath
if (-not [string]::IsNullOrWhiteSpace($parent)) {
New-Item -ItemType Directory -Force -Path $parent | Out-Null
}
Set-Content -LiteralPath $EvidencePath -Value "W24_DEMO_START runId=$RunId" -Encoding utf8
function Invoke-DemoStep([string]$Script, [string[]]$Arguments) {
$raw = @(& powershell.exe -NoProfile -ExecutionPolicy Bypass -File $Script @Arguments 2>&1)
$exitCode = $LASTEXITCODE
$raw | Add-Content -LiteralPath $EvidencePath -Encoding utf8
if ($exitCode -ne 0) {
throw "$Script failed exit=$exitCode`n$($raw -join "`n")"
}
return @($raw | ForEach-Object { [string]$_ })
}
$state = Join-Path (Split-Path -Parent $EvidencePath) 'demo-state.json'
$key = "demo-$RunId"
$resetArguments = @('-RunId', $RunId, '-StatePath', $state)
if (-not [string]::IsNullOrWhiteSpace($BaseUrl)) { $resetArguments += @('-BaseUrl', $BaseUrl) }
Invoke-DemoStep '.\scripts\reset-demo.ps1' $resetArguments | Out-Null
Invoke-DemoStep '.\scripts\run-transfer.ps1' @('-Key', $key, '-Amount', '1000', '-ExpectedStatus', '201', '-StatePath', $state) | Out-Null
Invoke-DemoStep '.\scripts\run-transfer.ps1' @('-Key', $key, '-Amount', '1000', '-ExpectedStatus', '200', '-StatePath', $state) | Out-Null
Invoke-DemoStep '.\scripts\run-transfer.ps1' @('-Key', $key, '-Amount', '2000', '-ExpectedStatus', '409', '-StatePath', $state) | Out-Null
Invoke-DemoStep '.\scripts\reconcile-demo.ps1' @('-StatePath', $state, '-Container', $Container) | Out-Null
$text = Get-Content -LiteralPath $EvidencePath -Raw
foreach ($marker in @(
'DEMO_RESET_OK',
"DEMO_TRANSFER_OK key=$key amount=1000 status=201",
"DEMO_TRANSFER_OK key=$key amount=1000 status=200",
"DEMO_TRANSFER_OK key=$key amount=2000 status=409",
'DEMO_RECONCILIATION_GREEN mismatches=0'
)) {
if ($text -cnotmatch [regex]::Escape($marker)) { throw "missing demo marker: $marker" }
}
$summary = 'W24_DEMO_GREEN first=201 replay=200 conflict=409 mismatches=0'
$summary | Add-Content -LiteralPath $EvidencePath -Encoding utf8
$summary
} finally {
Pop-Location
}
STEP 06 / 13
코드 한 줄씩 한국어로 번역
비어 있지 않은 50줄을 모두 한국어로 옮깁니다.
비어 있지 않은 원본 줄은 하나도 생략하지 않습니다.
| 줄 | 원본 | 한국어 번역 |
|---|---|---|
| 1 | param( | 실행 의미: PowerShell script가 받을 입력 계약을 연다. |
| 2 | [string]$RunId = "w24-$([DateTimeOffset]::UtcNow.ToUnixTimeMilliseconds())", | 실행 의미: run-w24-demo.ps1의 다음 검증 또는 설명 단계를 구성한다. |
| 3 | [string]$EvidencePath = 'evidence\w24\demo-run.txt', | 실행 의미: run-w24-demo.ps1의 다음 검증 또는 설명 단계를 구성한다. |
| 4 | [string]$BaseUrl = '', | 실행 의미: run-w24-demo.ps1의 다음 검증 또는 설명 단계를 구성한다. |
| 5 | [Parameter(Mandatory=$true)][string]$Container | 실행 의미: 이 인자가 빠지면 실행 시작 전에 binding을 거절한다. |
| 6 | ) | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 8 | $ErrorActionPreference = 'Stop' | 실행 의미: PowerShell 오류를 계속 진행하지 않고 중단시키는 기본 정책을 둔다. |
| 9 | $project = Split-Path -Parent $PSScriptRoot | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 10 | Push-Location $project | 실행 의미: run-w24-demo.ps1의 다음 검증 또는 설명 단계를 구성한다. |
| 11 | try { | 실행 의미: 조건·반복·함수의 실행 block을 연다. |
| 12 | $EvidencePath = [IO.Path]::GetFullPath($EvidencePath) | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 13 | $parent = Split-Path -Parent $EvidencePath | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 14 | if (-not [string]::IsNullOrWhiteSpace($parent)) { | 실행 의미: 조건·반복·함수의 실행 block을 연다. |
| 15 | New-Item -ItemType Directory -Force -Path $parent | Out-Null | 실행 의미: Markdown 표 또는 PowerShell pipeline에서 값을 열이나 다음 명령으로 연결한다. |
| 16 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 17 | Set-Content -LiteralPath $EvidencePath -Value "W24_DEMO_START runId=$RunId" -Encoding utf8 | 실행 의미: run-w24-demo.ps1의 다음 검증 또는 설명 단계를 구성한다. |
| 19 | function Invoke-DemoStep([string]$Script, [string[]]$Arguments) { | 실행 의미: 조건·반복·함수의 실행 block을 연다. |
| 20 | $raw = @(& powershell.exe -NoProfile -ExecutionPolicy Bypass -File $Script @Arguments 2>&1) | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 21 | $exitCode = $LASTEXITCODE | 실행 의미: native process 종료 코드를 검사해 실패를 놓치지 않는다. |
| 22 | $raw | Add-Content -LiteralPath $EvidencePath -Encoding utf8 | 실행 의미: Markdown 표 또는 PowerShell pipeline에서 값을 열이나 다음 명령으로 연결한다. |
| 23 | if ($exitCode -ne 0) { | 실행 의미: 조건·반복·함수의 실행 block을 연다. |
| 24 | throw "$Script failed exit=$exitCode`n$($raw -join "`n")" | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 25 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 26 | return @($raw | ForEach-Object { [string]$_ }) | 실행 의미: 고정 목록의 각 항목에 같은 검사를 반복 적용한다. |
| 27 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 29 | $state = Join-Path (Split-Path -Parent $EvidencePath) 'demo-state.json' | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 30 | $key = "demo-$RunId" | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 31 | $resetArguments = @('-RunId', $RunId, '-StatePath', $state) | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 32 | if (-not [string]::IsNullOrWhiteSpace($BaseUrl)) { $resetArguments += @('-BaseUrl', $BaseUrl) } | 실행 의미: run-w24-demo.ps1의 다음 검증 또는 설명 단계를 구성한다. |
| 33 | Invoke-DemoStep '.\scripts\reset-demo.ps1' $resetArguments | Out-Null | 실행 의미: Markdown 표 또는 PowerShell pipeline에서 값을 열이나 다음 명령으로 연결한다. |
| 34 | Invoke-DemoStep '.\scripts\run-transfer.ps1' @('-Key', $key, '-Amount', '1000', '-ExpectedStatus', '201', '-StatePath', $state) | Out-Null | 실행 의미: 각 demo 단계가 반드시 반환해야 할 HTTP status를 입력으로 고정한다. |
| 35 | Invoke-DemoStep '.\scripts\run-transfer.ps1' @('-Key', $key, '-Amount', '1000', '-ExpectedStatus', '200', '-StatePath', $state) | Out-Null | 실행 의미: 각 demo 단계가 반드시 반환해야 할 HTTP status를 입력으로 고정한다. |
| 36 | Invoke-DemoStep '.\scripts\run-transfer.ps1' @('-Key', $key, '-Amount', '2000', '-ExpectedStatus', '409', '-StatePath', $state) | Out-Null | 실행 의미: 각 demo 단계가 반드시 반환해야 할 HTTP status를 입력으로 고정한다. |
| 37 | Invoke-DemoStep '.\scripts\reconcile-demo.ps1' @('-StatePath', $state, '-Container', $Container) | Out-Null | 실행 의미: Markdown 표 또는 PowerShell pipeline에서 값을 열이나 다음 명령으로 연결한다. |
| 39 | $text = Get-Content -LiteralPath $EvidencePath -Raw | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 40 | foreach ($marker in @( | 실행 의미: 고정 목록의 각 항목에 같은 검사를 반복 적용한다. |
| 41 | 'DEMO_RESET_OK', | 실행 의미: 두 numeric account ID가 state에 저장된 reset 완료 marker를 낸다. |
| 42 | "DEMO_TRANSFER_OK key=$key amount=1000 status=201", | 실행 의미: 한 transfer 호출이 기대 status와 일치했음을 transcript에 남긴다. |
| 43 | "DEMO_TRANSFER_OK key=$key amount=1000 status=200", | 실행 의미: 한 transfer 호출이 기대 status와 일치했음을 transcript에 남긴다. |
| 44 | "DEMO_TRANSFER_OK key=$key amount=2000 status=409", | 실행 의미: 한 transfer 호출이 기대 status와 일치했음을 transcript에 남긴다. |
| 45 | 'DEMO_RECONCILIATION_GREEN mismatches=0' | 실행 의미: account balance와 ledger 합계를 비교해 mismatch를 찾는다. |
| 46 | )) { | 실행 의미: 조건·반복·함수의 실행 block을 연다. |
| 47 | if ($text -cnotmatch [regex]::Escape($marker)) { throw "missing demo marker: $marker" } | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 48 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 49 | $summary = 'W24_DEMO_GREEN first=201 replay=200 conflict=409 mismatches=0' | 실행 의미: 201→200→409→대사0 exact marker가 모두 있을 때 demo 범위를 닫는다. |
| 50 | $summary | Add-Content -LiteralPath $EvidencePath -Encoding utf8 | 실행 의미: Markdown 표 또는 PowerShell pipeline에서 값을 열이나 다음 명령으로 연결한다. |
| 51 | $summary | 실행 의미: run-w24-demo.ps1의 다음 검증 또는 설명 단계를 구성한다. |
| 52 | } finally { | 실행 의미: 중간 실패가 있어도 반드시 실행할 cleanup 경계를 연다. |
| 53 | Pop-Location | 실행 의미: run-w24-demo.ps1의 다음 검증 또는 설명 단계를 구성한다. |
| 54 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
STEP 07 / 13
기존 수준의 한 줄 읽기·문법 해부
쉬운 설명 다음에 문법과 실행 순서를 정밀하게 읽습니다.
한 줄로 읽기run-w24-demo.ps1 — reset→201→200→409→대사0 orchestration는 네 packaged script를 같은 runId·state·transcript로 묶고 모든 exact marker가 있을 때만 W24_DEMO_GREEN을 발행한다.
문법 해부
- .ps1 문법에서 선언·조건·pipeline·block 경계를 먼저 나눈다.
- expected 값과 actual 결과를 같은 이름처럼 보여도 서로 다른 source로 읽는다.
- native exit·row count·hash·사람 판정을 서로 대체하지 않는다.
실행 순서
- 입력 경로·fixture·환경변수·expected 계약을 고정한다.
- source가 실행하는 native process·HTTP·SQL 또는 형식 검사를 따라간다.
- actual 값과 exact marker를 대조하고 실패면 성공 발행 전에 중단한다.
- finally cleanup과 비범위를 evidence에 남긴다.
W24 조각별 정밀 해설
F11-C01 · 원문 1–12줄
- 문법 해부
- .ps1 문법으로 1–12줄의 선언·조건·pipeline·block을 나눈다.
- 실제 값 추적
- first=201, replay=200, conflict=409를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- expected와 actual이 일치하고 owner evidence가 같은 run/hash에 연결되는 경우다.
- 틀린 예·반례
- 앱/DB lifecycle은 D7이 소유한다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- 파일 존재·문자열·hash·exit0 하나를 의미 Green 전체와 같다고 보지 않는다.
- 하지 않는 일
- 앱/DB lifecycle은 D7이 소유한다; marker 하나라도 없으면 실패한다; source audit만으로 runtime Green이 아니다
- 다음 연결
- 다음 조각 또는 F11 evidence 판정으로 상태를 넘긴다.
F11-C02 · 원문 13–24줄
- 문법 해부
- .ps1 문법으로 13–24줄의 선언·조건·pipeline·block을 나눈다.
- 실제 값 추적
- first=201, replay=200, conflict=409를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- expected와 actual이 일치하고 owner evidence가 같은 run/hash에 연결되는 경우다.
- 틀린 예·반례
- 앱/DB lifecycle은 D7이 소유한다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- 파일 존재·문자열·hash·exit0 하나를 의미 Green 전체와 같다고 보지 않는다.
- 하지 않는 일
- 앱/DB lifecycle은 D7이 소유한다; marker 하나라도 없으면 실패한다; source audit만으로 runtime Green이 아니다
- 다음 연결
- 다음 조각 또는 F11 evidence 판정으로 상태를 넘긴다.
F11-C03 · 원문 25–36줄
- 문법 해부
- .ps1 문법으로 25–36줄의 선언·조건·pipeline·block을 나눈다.
- 실제 값 추적
- first=201, replay=200, conflict=409를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- expected와 actual이 일치하고 owner evidence가 같은 run/hash에 연결되는 경우다.
- 틀린 예·반례
- 앱/DB lifecycle은 D7이 소유한다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- 파일 존재·문자열·hash·exit0 하나를 의미 Green 전체와 같다고 보지 않는다.
- 하지 않는 일
- 앱/DB lifecycle은 D7이 소유한다; marker 하나라도 없으면 실패한다; source audit만으로 runtime Green이 아니다
- 다음 연결
- 다음 조각 또는 F11 evidence 판정으로 상태를 넘긴다.
F11-C04 · 원문 37–48줄
- 문법 해부
- .ps1 문법으로 37–48줄의 선언·조건·pipeline·block을 나눈다.
- 실제 값 추적
- first=201, replay=200, conflict=409를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- expected와 actual이 일치하고 owner evidence가 같은 run/hash에 연결되는 경우다.
- 틀린 예·반례
- 앱/DB lifecycle은 D7이 소유한다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- 파일 존재·문자열·hash·exit0 하나를 의미 Green 전체와 같다고 보지 않는다.
- 하지 않는 일
- 앱/DB lifecycle은 D7이 소유한다; marker 하나라도 없으면 실패한다; source audit만으로 runtime Green이 아니다
- 다음 연결
- 다음 조각 또는 F11 evidence 판정으로 상태를 넘긴다.
F11-C05 · 원문 49–54줄
- 문법 해부
- .ps1 문법으로 49–54줄의 선언·조건·pipeline·block을 나눈다.
- 실제 값 추적
- first=201, replay=200, conflict=409를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- expected와 actual이 일치하고 owner evidence가 같은 run/hash에 연결되는 경우다.
- 틀린 예·반례
- 앱/DB lifecycle은 D7이 소유한다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- 파일 존재·문자열·hash·exit0 하나를 의미 Green 전체와 같다고 보지 않는다.
- 하지 않는 일
- 앱/DB lifecycle은 D7이 소유한다; marker 하나라도 없으면 실패한다; source audit만으로 runtime Green이 아니다
- 다음 연결
- 다음 조각 또는 F11 evidence 판정으로 상태를 넘긴다.
실행 순서 — run-w24-demo.ps1 — reset→201→200→409→대사0 orchestration
-
replay=200가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 네 packaged script를 같은 runId·state·transcript로 묶고 모든 exact marker가 있을 때만 W24_DEMO_GREEN을 발행한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘marker 하나라도 없으면 실패한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 replay=200와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 08 / 13
실제 값 따라가기
같은 입력값이 어느 줄을 지나 어떤 결과가 되는지 추적합니다.
| 순서 | 들어온 값 | 코드가 하는 일 | 나온 값·상태 | 경계 |
|---|---|---|---|---|
| 입력 | first=201 | source 계약에 대입 | F11 실행/설명 시작 상태 | 앱/DB lifecycle은 D7이 소유한다 |
| 검증 | replay=200 | expected와 actual 또는 형식 대조 | 통과 또는 첫 mismatch | marker 하나라도 없으면 실패한다 |
| 증거 | same runId | marker·hash·row를 같은 run에 연결 | 범위가 적힌 evidence 후보 | source audit만으로 runtime Green이 아니다 |
실제 값 — run-w24-demo.ps1 — reset→201→200→409→대사0 orchestration
-
conflict=409가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 네 packaged script를 같은 runId·state·transcript로 묶고 모든 exact marker가 있을 때만 W24_DEMO_GREEN을 발행한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘source audit만으로 runtime Green이 아니다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 conflict=409와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 09 / 13
Gradle·PowerShell·HTTP·PostgreSQL 내부에서 벌어지는 일
Gradle·JUnit XML·PowerShell·HTTP·PostgreSQL·Docker에서 실제로 일어나는 일과 증명 범위를 구분합니다.
run-w24-demo.ps1 bytes와 expected 값을 읽는다.
파일 존재만으로 runtime 성공은 아니다.native exit·HTTP status·JUnit XML·DB row·hash 중 이 파일이 소유한 값을 만든다.
앱/DB lifecycle은 D7이 소유한다관련 evidence와 사람 의미 검토를 release 후보에 연결한다.
source audit만으로 runtime Green이 아니다첫 실패 경계 — run-w24-demo.ps1 — reset→201→200→409→대사0 orchestration
-
mismatches=0가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 네 packaged script를 같은 runId·state·transcript로 묶고 모든 exact marker가 있을 때만 W24_DEMO_GREEN을 발행한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘앱/DB lifecycle은 D7이 소유한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 mismatches=0와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 10 / 13
흔한 착각과 틀린 예
그럴듯하지만 틀린 해석을 반례로 고칩니다.
❌ first=201 문자열이 source에 있으니 실제 실행도 Green이다.
왜 틀리나 source literal과 runtime 관찰값은 다른 증거다.
바르게 읽기 native exit·actual XML/HTTP/DB evidence를 별도로 확인한다.
반례 script가 실행 전 경로 오류로 멈춰도 literal은 그대로 남는다.
❌ 파일 SHA-256이 있으면 내용의 의미와 사실성도 검증됐다.
왜 틀리나 hash는 동일 bytes만 말한다.
바르게 읽기 schema·수치·질문·근거는 별도 자동 또는 사람 판정을 거친다.
반례 빈 review 질문을 가진 CSV도 안정된 hash를 가진다.
❌ LOCAL_ARTIFACT_VALIDATED는 release Green과 같다.
왜 틀리나 generic validator는 파일 shape만 확인한다.
바르게 읽기 HUMAN_SEMANTIC_REVIEW_REQUIRED를 유지한다.
반례 잘못된 track 점수표도 byte 수 조건은 통과할 수 있다.
❌ 이 파일이 W24 전체 lifecycle을 모두 소유한다.
왜 틀리나 각 source는 Gate·demo·cleanup·사람 review 중 일부만 담당한다.
바르게 읽기 owner와 non-responsibility를 release manifest에서 분리한다.
반례 D4 source audit에는 runtime_claim=false가 명시된다.
❌ 이전 주 Green이나 오래된 log를 현재 commit 결과로 재사용한다.
왜 틀리나 source·commit·actual result가 같은 실행에 묶이지 않는다.
바르게 읽기 release 후보에서 새 evidence와 hash를 만든다.
반례 expected JSON이 바뀌면 예전 XML은 exact inventory를 증명하지 못한다.
STEP 11 / 13
이 코드가 보장하지 않는 것
이 코드가 책임지지 않는 일을 분리합니다.
앱/DB lifecycle은 D7이 소유한다
이 책임을 맡는 곳: runtime Gatemarker 하나라도 없으면 실패한다
이 책임을 맡는 곳: external/human reviewsource audit만으로 runtime Green이 아니다
이 책임을 맡는 곳: release manifest앱/DB lifecycle은 D7이 소유한다
이 책임을 맡는 곳: 운영 환경증명하지 않는 범위 — run-w24-demo.ps1 — reset→201→200→409→대사0 orchestration
-
same runId가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 네 packaged script를 같은 runId·state·transcript로 묶고 모든 exact marker가 있을 때만 W24_DEMO_GREEN을 발행한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘marker 하나라도 없으면 실패한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 same runId와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 12 / 13
직접 다시 써보기
뜻 → 조각 → 전체 코드 순서로 다시 씁니다.
1단계 · 뜻부터 복원
- 네 packaged script를 같은 runId·state·transcript로 묶고 모든 exact marker가 있을 때만 W24_DEMO_GREEN을 발행한다.
- 핵심 값은 first=201, replay=200, conflict=409, mismatches=0, same runId다.
2단계 · 코드 조각 재조립
- 1. PowerShell script가 받을 입력 계약을 연다
- 2. run-w24-demo.ps1의 다음 검증 또는 설명 단계를 구성한다
- 3. run-w24-demo.ps1의 다음 검증 또는 설명 단계를 구성한다
- 4. run-w24-demo.ps1의 다음 검증 또는 설명 단계를 구성한다
- 5. 이 인자가 빠지면 실행 시작 전에 binding을 거절한다
- 6. 앞에서 연 block 또는 호출 범위를 닫는다
- 8. PowerShell 오류를 계속 진행하지 않고 중단시키는 기본 정책을 둔다
- 9. 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다
3단계 · 파일 전체 다시 쓰기
scripts/run-w24-demo.ps1을 새 파일에 다시 쓰고 expected·actual·실패·cleanup·비범위를 주석으로 표시한다.
자가 점검
- 비어 있지 않은 모든 source 줄을 한 번씩 읽었나?
- source shape와 runtime Green을 분리했나?
- 사람 검토·외부 상태를 자동 성공으로 꾸미지 않았나?
- 첫 실패와 cleanup 책임을 설명할 수 있나?
STEP 13 / 13
전체 원본 source
감사로 고정한 전체 source를 가감 없이 확인합니다.
원문 정본 전체 source 확인하기
param(
[string]$RunId = "w24-$([DateTimeOffset]::UtcNow.ToUnixTimeMilliseconds())",
[string]$EvidencePath = 'evidence\w24\demo-run.txt',
[string]$BaseUrl = '',
[Parameter(Mandatory=$true)][string]$Container
)
$ErrorActionPreference = 'Stop'
$project = Split-Path -Parent $PSScriptRoot
Push-Location $project
try {
$EvidencePath = [IO.Path]::GetFullPath($EvidencePath)
$parent = Split-Path -Parent $EvidencePath
if (-not [string]::IsNullOrWhiteSpace($parent)) {
New-Item -ItemType Directory -Force -Path $parent | Out-Null
}
Set-Content -LiteralPath $EvidencePath -Value "W24_DEMO_START runId=$RunId" -Encoding utf8
function Invoke-DemoStep([string]$Script, [string[]]$Arguments) {
$raw = @(& powershell.exe -NoProfile -ExecutionPolicy Bypass -File $Script @Arguments 2>&1)
$exitCode = $LASTEXITCODE
$raw | Add-Content -LiteralPath $EvidencePath -Encoding utf8
if ($exitCode -ne 0) {
throw "$Script failed exit=$exitCode`n$($raw -join "`n")"
}
return @($raw | ForEach-Object { [string]$_ })
}
$state = Join-Path (Split-Path -Parent $EvidencePath) 'demo-state.json'
$key = "demo-$RunId"
$resetArguments = @('-RunId', $RunId, '-StatePath', $state)
if (-not [string]::IsNullOrWhiteSpace($BaseUrl)) { $resetArguments += @('-BaseUrl', $BaseUrl) }
Invoke-DemoStep '.\scripts\reset-demo.ps1' $resetArguments | Out-Null
Invoke-DemoStep '.\scripts\run-transfer.ps1' @('-Key', $key, '-Amount', '1000', '-ExpectedStatus', '201', '-StatePath', $state) | Out-Null
Invoke-DemoStep '.\scripts\run-transfer.ps1' @('-Key', $key, '-Amount', '1000', '-ExpectedStatus', '200', '-StatePath', $state) | Out-Null
Invoke-DemoStep '.\scripts\run-transfer.ps1' @('-Key', $key, '-Amount', '2000', '-ExpectedStatus', '409', '-StatePath', $state) | Out-Null
Invoke-DemoStep '.\scripts\reconcile-demo.ps1' @('-StatePath', $state, '-Container', $Container) | Out-Null
$text = Get-Content -LiteralPath $EvidencePath -Raw
foreach ($marker in @(
'DEMO_RESET_OK',
"DEMO_TRANSFER_OK key=$key amount=1000 status=201",
"DEMO_TRANSFER_OK key=$key amount=1000 status=200",
"DEMO_TRANSFER_OK key=$key amount=2000 status=409",
'DEMO_RECONCILIATION_GREEN mismatches=0'
)) {
if ($text -cnotmatch [regex]::Escape($marker)) { throw "missing demo marker: $marker" }
}
$summary = 'W24_DEMO_GREEN first=201 replay=200 conflict=409 mismatches=0'
$summary | Add-Content -LiteralPath $EvidencePath -Encoding utf8
$summary
} finally {
Pop-Location
}
12W24 D4 source audit — 4개 demo script hash와 literal secret 검사
illustrative/powershell/W24-D4-demo-source-audit.ps1
학습용 예시 · PDF inline PowerShell · 정본 답안 아님 · 비실행 · 학습용 예시 · 정본 답안 아님 · W24-F1223줄 연결23줄 번역2 chunks
W24 D4 source audit — 4개 demo script hash와 literal secret 검사
illustrative/powershell/W24-D4-demo-source-audit.ps1
학습용 예시 · PDF inline PowerShell · 정본 답안 아님 · 비실행 · 학습용 예시 · 정본 답안 아님 · W24-F12STEP 01 / 13
오늘 이 코드에서 해결할 문제
무엇을 이해해야 하는지 질문부터 잡습니다.
packaged demo source 4개의 존재·bytes·SHA-256과 단순 literal secret 패턴만 검사해 runtime_claim=false evidence를 만든다.
- files=4은 어느 source와 실제 결과에서 확인해야 할까?
- 첫 실패를 만드는 조건과 fail-closed 지점은 어디일까?
- 왜 ‘PDF-only 학습 예시다’를 별도 경계로 남겨야 할까?
files=4literal_secrets=0hashes=4runtime_claim=false왜 필요한가 — W24 D4 source audit — 4개 demo script hash와 literal secret 검사
-
files=4가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 packaged demo source 4개의 존재·bytes·SHA-256과 단순 literal secret 패턴만 검사해 runtime_claim=false evidence를 만든다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘PDF-only 학습 예시다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 files=4와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 02 / 13
아주 짧게: 이 코드는 왜 필요할까?
웹소설 대신 이 코드가 필요한 이유만 두 문단으로 쉽게 봅니다.
새 기능을 멈춘 팀이 코드·test·문서·demo를 같은 release 후보에 묶어 하나씩 검수한다.
검수 도장이 붙은 공통 거래 코어 출고 상자
이 파일은 packaged demo source 4개의 존재·bytes·SHA-256과 단순 literal secret 패턴만 검사해 runtime_claim=false evidence를 만든다. 눈으로 읽을 때는 각 줄을 검수표 한 칸처럼 보고, 입력과 다음 상태를 놓치지 않는다.
마지막 도장은 source shape와 실제 runtime·사람 검토를 구분한 뒤에만 찍는다. 특히 PDF-only 학습 예시다
딱 여기까지만 비유는 실행 순서를 돕지만 실제 Gradle·Docker·DB·사람 review를 대신하지 않는다.
STEP 03 / 13
초등학생도 이해하는 설명
생활 비유와 실제 코드의 경계를 함께 확인합니다.
값 1: files=4
이 파일에서 계속 확인할 고정 단서가 files=4다.
- 코드 연결
F12 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- PDF-only 학습 예시다
값 2: literal_secrets=0
이 파일에서 계속 확인할 고정 단서가 literal_secrets=0다.
- 코드 연결
F12 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- DB/app을 실행하지 않는다
값 3: hashes=4
이 파일에서 계속 확인할 고정 단서가 hashes=4다.
- 코드 연결
F12 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- 실제 201→200→409→대사0 Green은 D7 책임이다
값 4: runtime_claim=false
이 파일에서 계속 확인할 고정 단서가 runtime_claim=false다.
- 코드 연결
F12 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- PDF-only 학습 예시다
STEP 04 / 13
비유 ↔ 코드 전체 연결표
감사 규칙상 연결 대상인 원본 23줄을 빠짐없이 연결합니다.
| 줄 | 정확한 원본 줄 | STARRY 비유 | 실제 뜻·입력·결과·한계 |
|---|---|---|---|
| 1줄F12-L01 | # W24 PDF p804의 source-only Gate를 읽기 좋게 정리한 학습용 예시다. |
출고표 1번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다.
|
| 2줄F12-L02 | # 이 검사는 active DB/ |
출고표 2번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다.
|
| 3줄F12-L03 | $Names = |
출고표 3번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 4줄F12-L04 | $Rows = |
출고표 4번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 5줄F12-L05 | foreach ( |
출고표 5번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 고정 목록의 각 항목에 같은 검사를 반복 적용한다.
|
| 6줄F12-L06 | $Path = |
출고표 6번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 7줄F12-L07 | if ( |
출고표 7번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 필수 파일이나 경로가 실제로 있는지 확인한다.
|
| 8줄F12-L08 | throw "missing packaged demo script: |
출고표 8번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 9줄F12-L09 | } |
출고표 9번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 10줄F12-L10 | $Text = |
출고표 10번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 11줄F12-L11 | if ( |
출고표 11번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 인증 header를 runtime에서 만들되 evidence에 원문 비밀을 남기지 않는다.
|
| 12줄F12-L12 | throw "literal secret in $Name" |
출고표 12번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 13줄F12-L13 | } |
출고표 13번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 14줄F12-L14 | $Rows + |
출고표 14번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 조건·반복·함수의 실행 block을 연다.
|
| 15줄F12-L15 | file = |
출고표 15번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W24-D4-demo-source-audit.ps1의 다음 검증 또는 설명 단계를 구성한다.
|
| 16줄F12-L16 | bytes = |
출고표 16번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W24-D4-demo-source-audit.ps1의 다음 검증 또는 설명 단계를 구성한다.
|
| 17줄F12-L17 | sha256 = |
출고표 17번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 현재 bytes를 64자리 digest로 evidence에 결박한다.
|
| 18줄F12-L18 | } |
출고표 18번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 19줄F12-L19 | } |
출고표 19번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 21줄F12-L21 | $Out = |
출고표 21번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 22줄F12-L22 | New-Item -ItemType Directory -Force ( |
출고표 22번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 Markdown 표 또는 PowerShell pipeline에서 값을 열이나 다음 명령으로 연결한다.
|
| 23줄F12-L23 | $Rows | ConvertTo-Json | Set-Content -Encoding utf8 $Out |
출고표 23번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 검증된 object를 JSON evidence text로 직렬화한다.
|
| 24줄F12-L24 | 'W24_DEMO_SOURCE_AUDIT files= |
출고표 24번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W24-D4-demo-source-audit.ps1의 다음 검증 또는 설명 단계를 구성한다.
|
STEP 05 / 13
원본 코드 조각
원본을 2개 의미 조각으로 나누어 그대로 확인합니다.
파일을 한꺼번에 외우지 않고 실행 의미가 이어지는 작은 조각으로 봅니다. 아래 코드는 prompt·fixture·가정을 밝힌 학습용 예시 source이며, 제공 정본 답안이 아닙니다.
# W24 PDF p804의 source-only Gate를 읽기 좋게 정리한 학습용 예시다.
# 이 검사는 active DB/app lifecycle을 실행하지 않으며 runtime Green을 주장하지 않는다.
$Names = @('reset-demo.ps1', 'run-transfer.ps1', 'reconcile-demo.ps1', 'run-w24-demo.ps1')
$Rows = @()
foreach ($Name in $Names) {
$Path = Join-Path $ReferenceRoot ('scripts\' + $Name)
if (!(Test-Path -LiteralPath $Path -PathType Leaf)) {
throw "missing packaged demo script: $Name"
}
$Text = Get-Content -Raw -LiteralPath $Path
if ($Text -cmatch '(?i)(password\s*=\s*["''][^$]|Authorization:\s*Basic\s+[A-Za-z0-9])') {
throw "literal secret in $Name"
}
$Rows += [ordered]@{
file = $Name
bytes = (Get-Item -LiteralPath $Path).Length
sha256 = (Get-FileHash -LiteralPath $Path -Algorithm SHA256).Hash.ToLowerInvariant()
}
}
$Out = Join-Path $LearnerRoot 'evidence\w24\demo-script-review.json'
New-Item -ItemType Directory -Force (Split-Path -Parent $Out) | Out-Null
$Rows | ConvertTo-Json | Set-Content -Encoding utf8 $Out
'W24_DEMO_SOURCE_AUDIT files=4 literal_secrets=0 hashes=4 runtime_claim=false'
STEP 06 / 13
코드 한 줄씩 한국어로 번역
비어 있지 않은 23줄을 모두 한국어로 옮깁니다.
비어 있지 않은 원본 줄은 하나도 생략하지 않습니다.
| 줄 | 원본 | 한국어 번역 |
|---|---|---|
| 1 | # W24 PDF p804의 source-only Gate를 읽기 좋게 정리한 학습용 예시다. | 문서 의미: 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다. |
| 2 | # 이 검사는 active DB/app lifecycle을 실행하지 않으며 runtime Green을 주장하지 않는다. | 문서 의미: 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다. |
| 3 | $Names = @('reset-demo.ps1', 'run-transfer.ps1', 'reconcile-demo.ps1', 'run-w24-demo.ps1') | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 4 | $Rows = @() | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 5 | foreach ($Name in $Names) { | 실행 의미: 고정 목록의 각 항목에 같은 검사를 반복 적용한다. |
| 6 | $Path = Join-Path $ReferenceRoot ('scripts\' + $Name) | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 7 | if (!(Test-Path -LiteralPath $Path -PathType Leaf)) { | 실행 의미: 필수 파일이나 경로가 실제로 있는지 확인한다. |
| 8 | throw "missing packaged demo script: $Name" | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 9 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 10 | $Text = Get-Content -Raw -LiteralPath $Path | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 11 | if ($Text -cmatch '(?i)(password\s*=\s*["''][^$]|Authorization:\s*Basic\s+[A-Za-z0-9])') { | 실행 의미: 인증 header를 runtime에서 만들되 evidence에 원문 비밀을 남기지 않는다. |
| 12 | throw "literal secret in $Name" | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 13 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 14 | $Rows += [ordered]@{ | 실행 의미: 조건·반복·함수의 실행 block을 연다. |
| 15 | file = $Name | 실행 의미: W24-D4-demo-source-audit.ps1의 다음 검증 또는 설명 단계를 구성한다. |
| 16 | bytes = (Get-Item -LiteralPath $Path).Length | 실행 의미: W24-D4-demo-source-audit.ps1의 다음 검증 또는 설명 단계를 구성한다. |
| 17 | sha256 = (Get-FileHash -LiteralPath $Path -Algorithm SHA256).Hash.ToLowerInvariant() | 실행 의미: 현재 bytes를 64자리 digest로 evidence에 결박한다. |
| 18 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 19 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 21 | $Out = Join-Path $LearnerRoot 'evidence\w24\demo-script-review.json' | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 22 | New-Item -ItemType Directory -Force (Split-Path -Parent $Out) | Out-Null | 실행 의미: Markdown 표 또는 PowerShell pipeline에서 값을 열이나 다음 명령으로 연결한다. |
| 23 | $Rows | ConvertTo-Json | Set-Content -Encoding utf8 $Out | 실행 의미: 검증된 object를 JSON evidence text로 직렬화한다. |
| 24 | 'W24_DEMO_SOURCE_AUDIT files=4 literal_secrets=0 hashes=4 runtime_claim=false' | 실행 의미: W24-D4-demo-source-audit.ps1의 다음 검증 또는 설명 단계를 구성한다. |
STEP 07 / 13
기존 수준의 한 줄 읽기·문법 해부
쉬운 설명 다음에 문법과 실행 순서를 정밀하게 읽습니다.
한 줄로 읽기W24 D4 source audit — 4개 demo script hash와 literal secret 검사는 packaged demo source 4개의 존재·bytes·SHA-256과 단순 literal secret 패턴만 검사해 runtime_claim=false evidence를 만든다.
문법 해부
- .ps1 문법에서 선언·조건·pipeline·block 경계를 먼저 나눈다.
- expected 값과 actual 결과를 같은 이름처럼 보여도 서로 다른 source로 읽는다.
- native exit·row count·hash·사람 판정을 서로 대체하지 않는다.
실행 순서
- 입력 경로·fixture·환경변수·expected 계약을 고정한다.
- source가 실행하는 native process·HTTP·SQL 또는 형식 검사를 따라간다.
- actual 값과 exact marker를 대조하고 실패면 성공 발행 전에 중단한다.
- finally cleanup과 비범위를 evidence에 남긴다.
W24 조각별 정밀 해설
F12-C01 · 원문 1–12줄
- 문법 해부
- .ps1 문법으로 1–12줄의 선언·조건·pipeline·block을 나눈다.
- 실제 값 추적
- files=4, literal_secrets=0, hashes=4를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- expected와 actual이 일치하고 owner evidence가 같은 run/hash에 연결되는 경우다.
- 틀린 예·반례
- PDF-only 학습 예시다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- 파일 존재·문자열·hash·exit0 하나를 의미 Green 전체와 같다고 보지 않는다.
- 하지 않는 일
- PDF-only 학습 예시다; DB/app을 실행하지 않는다; 실제 201→200→409→대사0 Green은 D7 책임이다
- 다음 연결
- 다음 조각 또는 F12 evidence 판정으로 상태를 넘긴다.
F12-C02 · 원문 13–24줄
- 문법 해부
- .ps1 문법으로 13–24줄의 선언·조건·pipeline·block을 나눈다.
- 실제 값 추적
- files=4, literal_secrets=0, hashes=4를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- expected와 actual이 일치하고 owner evidence가 같은 run/hash에 연결되는 경우다.
- 틀린 예·반례
- PDF-only 학습 예시다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- 파일 존재·문자열·hash·exit0 하나를 의미 Green 전체와 같다고 보지 않는다.
- 하지 않는 일
- PDF-only 학습 예시다; DB/app을 실행하지 않는다; 실제 201→200→409→대사0 Green은 D7 책임이다
- 다음 연결
- 다음 조각 또는 F12 evidence 판정으로 상태를 넘긴다.
실행 순서 — W24 D4 source audit — 4개 demo script hash와 literal secret 검사
-
literal_secrets=0가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 packaged demo source 4개의 존재·bytes·SHA-256과 단순 literal secret 패턴만 검사해 runtime_claim=false evidence를 만든다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘DB/app을 실행하지 않는다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 literal_secrets=0와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 08 / 13
실제 값 따라가기
같은 입력값이 어느 줄을 지나 어떤 결과가 되는지 추적합니다.
| 순서 | 들어온 값 | 코드가 하는 일 | 나온 값·상태 | 경계 |
|---|---|---|---|---|
| 입력 | files=4 | source 계약에 대입 | F12 실행/설명 시작 상태 | PDF-only 학습 예시다 |
| 검증 | literal_secrets=0 | expected와 actual 또는 형식 대조 | 통과 또는 첫 mismatch | DB/app을 실행하지 않는다 |
| 증거 | runtime_claim=false | marker·hash·row를 같은 run에 연결 | 범위가 적힌 evidence 후보 | 실제 201→200→409→대사0 Green은 D7 책임이다 |
실제 값 — W24 D4 source audit — 4개 demo script hash와 literal secret 검사
-
hashes=4가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 packaged demo source 4개의 존재·bytes·SHA-256과 단순 literal secret 패턴만 검사해 runtime_claim=false evidence를 만든다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘실제 201→200→409→대사0 Green은 D7 책임이다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 hashes=4와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 09 / 13
Gradle·PowerShell·HTTP·PostgreSQL 내부에서 벌어지는 일
Gradle·JUnit XML·PowerShell·HTTP·PostgreSQL·Docker에서 실제로 일어나는 일과 증명 범위를 구분합니다.
W24-D4-demo-source-audit.ps1 bytes와 expected 값을 읽는다.
파일 존재만으로 runtime 성공은 아니다.native exit·HTTP status·JUnit XML·DB row·hash 중 이 파일이 소유한 값을 만든다.
PDF-only 학습 예시다관련 evidence와 사람 의미 검토를 release 후보에 연결한다.
실제 201→200→409→대사0 Green은 D7 책임이다첫 실패 경계 — W24 D4 source audit — 4개 demo script hash와 literal secret 검사
-
runtime_claim=false가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 packaged demo source 4개의 존재·bytes·SHA-256과 단순 literal secret 패턴만 검사해 runtime_claim=false evidence를 만든다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘PDF-only 학습 예시다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 runtime_claim=false와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 10 / 13
흔한 착각과 틀린 예
그럴듯하지만 틀린 해석을 반례로 고칩니다.
❌ files=4 문자열이 source에 있으니 실제 실행도 Green이다.
왜 틀리나 source literal과 runtime 관찰값은 다른 증거다.
바르게 읽기 native exit·actual XML/HTTP/DB evidence를 별도로 확인한다.
반례 script가 실행 전 경로 오류로 멈춰도 literal은 그대로 남는다.
❌ 파일 SHA-256이 있으면 내용의 의미와 사실성도 검증됐다.
왜 틀리나 hash는 동일 bytes만 말한다.
바르게 읽기 schema·수치·질문·근거는 별도 자동 또는 사람 판정을 거친다.
반례 빈 review 질문을 가진 CSV도 안정된 hash를 가진다.
❌ LOCAL_ARTIFACT_VALIDATED는 release Green과 같다.
왜 틀리나 generic validator는 파일 shape만 확인한다.
바르게 읽기 HUMAN_SEMANTIC_REVIEW_REQUIRED를 유지한다.
반례 잘못된 track 점수표도 byte 수 조건은 통과할 수 있다.
❌ 이 파일이 W24 전체 lifecycle을 모두 소유한다.
왜 틀리나 각 source는 Gate·demo·cleanup·사람 review 중 일부만 담당한다.
바르게 읽기 owner와 non-responsibility를 release manifest에서 분리한다.
반례 D4 source audit에는 runtime_claim=false가 명시된다.
❌ 이전 주 Green이나 오래된 log를 현재 commit 결과로 재사용한다.
왜 틀리나 source·commit·actual result가 같은 실행에 묶이지 않는다.
바르게 읽기 release 후보에서 새 evidence와 hash를 만든다.
반례 expected JSON이 바뀌면 예전 XML은 exact inventory를 증명하지 못한다.
STEP 11 / 13
이 코드가 보장하지 않는 것
이 코드가 책임지지 않는 일을 분리합니다.
PDF-only 학습 예시다
이 책임을 맡는 곳: runtime GateDB/app을 실행하지 않는다
이 책임을 맡는 곳: external/human review실제 201→200→409→대사0 Green은 D7 책임이다
이 책임을 맡는 곳: release manifestPDF-only 학습 예시다
이 책임을 맡는 곳: 운영 환경증명하지 않는 범위 — W24 D4 source audit — 4개 demo script hash와 literal secret 검사
-
files=4가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 packaged demo source 4개의 존재·bytes·SHA-256과 단순 literal secret 패턴만 검사해 runtime_claim=false evidence를 만든다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘DB/app을 실행하지 않는다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 files=4와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 12 / 13
직접 다시 써보기
뜻 → 조각 → 전체 코드 순서로 다시 씁니다.
1단계 · 뜻부터 복원
- packaged demo source 4개의 존재·bytes·SHA-256과 단순 literal secret 패턴만 검사해 runtime_claim=false evidence를 만든다.
- 핵심 값은 files=4, literal_secrets=0, hashes=4, runtime_claim=false다.
2단계 · 코드 조각 재조립
- 1. 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다
- 2. 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다
- 3. 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다
- 4. 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다
- 5. 고정 목록의 각 항목에 같은 검사를 반복 적용한다
- 6. 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다
- 7. 필수 파일이나 경로가 실제로 있는지 확인한다
- 8. 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다
3단계 · 파일 전체 다시 쓰기
illustrative/powershell/W24-D4-demo-source-audit.ps1을 새 파일에 다시 쓰고 expected·actual·실패·cleanup·비범위를 주석으로 표시한다.
자가 점검
- 비어 있지 않은 모든 source 줄을 한 번씩 읽었나?
- source shape와 runtime Green을 분리했나?
- 사람 검토·외부 상태를 자동 성공으로 꾸미지 않았나?
- 첫 실패와 cleanup 책임을 설명할 수 있나?
STEP 13 / 13
전체 원본 source
감사로 고정한 전체 source를 가감 없이 확인합니다.
학습용 예시 전체 확인하기 · 정본 답안 아님
# W24 PDF p804의 source-only Gate를 읽기 좋게 정리한 학습용 예시다.
# 이 검사는 active DB/app lifecycle을 실행하지 않으며 runtime Green을 주장하지 않는다.
$Names = @('reset-demo.ps1', 'run-transfer.ps1', 'reconcile-demo.ps1', 'run-w24-demo.ps1')
$Rows = @()
foreach ($Name in $Names) {
$Path = Join-Path $ReferenceRoot ('scripts\' + $Name)
if (!(Test-Path -LiteralPath $Path -PathType Leaf)) {
throw "missing packaged demo script: $Name"
}
$Text = Get-Content -Raw -LiteralPath $Path
if ($Text -cmatch '(?i)(password\s*=\s*["''][^$]|Authorization:\s*Basic\s+[A-Za-z0-9])') {
throw "literal secret in $Name"
}
$Rows += [ordered]@{
file = $Name
bytes = (Get-Item -LiteralPath $Path).Length
sha256 = (Get-FileHash -LiteralPath $Path -Algorithm SHA256).Hash.ToLowerInvariant()
}
}
$Out = Join-Path $LearnerRoot 'evidence\w24\demo-script-review.json'
New-Item -ItemType Directory -Force (Split-Path -Parent $Out) | Out-Null
$Rows | ConvertTo-Json | Set-Content -Encoding utf8 $Out
'W24_DEMO_SOURCE_AUDIT files=4 literal_secrets=0 hashes=4 runtime_claim=false'
13W24 D5 external review — 형식 검사와 사람 의미 검증 분리
illustrative/markdown/W24-D5-external-review.md
학습용 예시 · PDF template/validator · 정본 답안 아님 · 학습용 예시 · 정본 답안 아님 · W24-F1331줄 연결31줄 번역4 chunks
W24 D5 external review — 형식 검사와 사람 의미 검증 분리
illustrative/markdown/W24-D5-external-review.md
학습용 예시 · PDF template/validator · 정본 답안 아님 · 학습용 예시 · 정본 답안 아님 · W24-F13STEP 01 / 13
오늘 이 코드에서 해결할 문제
무엇을 이해해야 하는지 질문부터 잡습니다.
reviewer 질문·decision·reason·commit/issue CSV 골격과 generic bytes/hash 검사를 보여 주고, 행별 사실성은 사람에게 남긴다.
- minimum 5 questions은 어느 source와 실제 결과에서 확인해야 할까?
- 첫 실패를 만드는 조건과 fail-closed 지점은 어디일까?
- 왜 ‘실제 external review가 아니다’를 별도 경계로 남겨야 할까?
minimum 5 questionsaccept/reject/deferLOCAL_ARTIFACT_VALIDATEDHUMAN_SEMANTIC_REVIEW_REQUIRED왜 필요한가 — W24 D5 external review — 형식 검사와 사람 의미 검증 분리
-
minimum 5 questions가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 reviewer 질문·decision·reason·commit/issue CSV 골격과 generic bytes/hash 검사를 보여 주고, 행별 사실성은 사람에게 남긴다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘실제 external review가 아니다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 minimum 5 questions와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 02 / 13
아주 짧게: 이 코드는 왜 필요할까?
웹소설 대신 이 코드가 필요한 이유만 두 문단으로 쉽게 봅니다.
새 기능을 멈춘 팀이 코드·test·문서·demo를 같은 release 후보에 묶어 하나씩 검수한다.
검수 도장이 붙은 공통 거래 코어 출고 상자
이 파일은 reviewer 질문·decision·reason·commit/issue CSV 골격과 generic bytes/hash 검사를 보여 주고, 행별 사실성은 사람에게 남긴다. 눈으로 읽을 때는 각 줄을 검수표 한 칸처럼 보고, 입력과 다음 상태를 놓치지 않는다.
마지막 도장은 source shape와 실제 runtime·사람 검토를 구분한 뒤에만 찍는다. 특히 실제 external review가 아니다
딱 여기까지만 비유는 실행 순서를 돕지만 실제 Gradle·Docker·DB·사람 review를 대신하지 않는다.
STEP 03 / 13
초등학생도 이해하는 설명
생활 비유와 실제 코드의 경계를 함께 확인합니다.
값 1: minimum 5 questions
이 파일에서 계속 확인할 고정 단서가 minimum 5 questions다.
- 코드 연결
F13 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- 실제 external review가 아니다
값 2: accept/reject/defer
이 파일에서 계속 확인할 고정 단서가 accept/reject/defer다.
- 코드 연결
F13 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- self-review로 대체하지 않는다
값 3: LOCAL_ARTIFACT_VALIDATED
이 파일에서 계속 확인할 고정 단서가 LOCAL_ARTIFACT_VALIDATED다.
- 코드 연결
F13 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- 빈 행 수를 review 품질로 세지 않는다
값 4: HUMAN_SEMANTIC_REVIEW_REQUIRED
이 파일에서 계속 확인할 고정 단서가 HUMAN_SEMANTIC_REVIEW_REQUIRED다.
- 코드 연결
F13 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- 실제 external review가 아니다
STEP 04 / 13
비유 ↔ 코드 전체 연결표
감사 규칙상 연결 대상인 원본 31줄을 빠짐없이 연결합니다.
| 줄 | 정확한 원본 줄 | STARRY 비유 | 실제 뜻·입력·결과·한계 |
|---|---|---|---|
| 1줄F13-L01 | # W24 D5 external review 학습 골격 |
출고표 1번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다.
|
| 3줄F13-L03 | > PDF p806–807의 TEMPLATE와 generic validator를 한 파일에 모았다. |
출고표 3번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W24-D5-external-review.md의 다음 검증 또는 설명 단계를 구성한다.
|
| 5줄F13-L05 | ## Review CSV template |
출고표 5번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다.
|
| 7줄F13-L07 | id, |
출고표 7번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W24-D5-external-review.md의 다음 검증 또는 설명 단계를 구성한다.
|
| 8줄F13-L08 | R1, |
출고표 8번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W24-D5-external-review.md의 다음 검증 또는 설명 단계를 구성한다.
|
| 9줄F13-L09 | R2, |
출고표 9번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W24-D5-external-review.md의 다음 검증 또는 설명 단계를 구성한다.
|
| 10줄F13-L10 | R3, |
출고표 10번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W24-D5-external-review.md의 다음 검증 또는 설명 단계를 구성한다.
|
| 12줄F13-L12 | ## 파일·hash 보조 검사 |
출고표 12번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다.
|
| 14줄F13-L14 | $Artifact = |
출고표 14번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 15줄F13-L15 | if ( |
출고표 15번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 필수 파일이나 경로가 실제로 있는지 확인한다.
|
| 16줄F13-L16 | throw "learner artifact missing: |
출고표 16번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 17줄F13-L17 | } |
출고표 17번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 18줄F13-L18 | $Item = |
출고표 18번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 19줄F13-L19 | if ( |
출고표 19번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 조건·반복·함수의 실행 block을 연다.
|
| 20줄F13-L20 | throw "artifact is too small to support the claim: |
출고표 20번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 21줄F13-L21 | } |
출고표 21번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 22줄F13-L22 | $Text = |
출고표 22번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 23줄F13-L23 | if ( |
출고표 23번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 Markdown 표 또는 PowerShell pipeline에서 값을 열이나 다음 명령으로 연결한다.
|
| 24줄F13-L24 | throw 'unresolved placeholder in learner artifact' |
출고표 24번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 25줄F13-L25 | } |
출고표 25번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 26줄F13-L26 | $NonBlank = |
출고표 26번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 조건을 만족하는 row만 필터링한다.
|
| 27줄F13-L27 | if ( |
출고표 27번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 조건·반복·함수의 실행 block을 연다.
|
| 28줄F13-L28 | throw "artifact needs at least three nonblank evidence lines: |
출고표 28번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 29줄F13-L29 | } |
출고표 29번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 30줄F13-L30 | $Hash = |
출고표 30번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 현재 bytes를 64자리 digest로 evidence에 결박한다.
|
| 31줄F13-L31 | "LOCAL_ARTIFACT_VALIDATED W24D5 bytes= |
출고표 31번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 파일 bytes·기본 형식·hash만 통과한 보조 marker를 낸다.
|
| 33줄F13-L33 | ## 반드시 남는 사람 판정 |
출고표 33번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다.
|
| 35줄F13-L35 | - 실제 reviewer identity·review 시각·대상 commit을 확인한다. |
출고표 35번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W24-D5-external-review.md의 다음 검증 또는 설명 단계를 구성한다.
|
| 36줄F13-L36 | - 최소 다섯 질문의 decision·reason·commit/ |
출고표 36번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W24-D5-external-review.md의 다음 검증 또는 설명 단계를 구성한다.
|
| 37줄F13-L37 | - LOCAL_ARTIFACT_VALIDATED는 Green이 아니다. |
출고표 37번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 파일 bytes·기본 형식·hash만 통과한 보조 marker를 낸다.
|
| 38줄F13-L38 | - 서명 전 상태는 HUMAN_SEMANTIC_REVIEW_REQUIRED다. |
출고표 38번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 review·점수·근거의 사실성을 사람이 대조해야 함을 고정한다.
|
STEP 05 / 13
원본 코드 조각
원본을 4개 의미 조각으로 나누어 그대로 확인합니다.
파일을 한꺼번에 외우지 않고 실행 의미가 이어지는 작은 조각으로 봅니다. 아래 코드는 prompt·fixture·가정을 밝힌 학습용 예시 source이며, 제공 정본 답안이 아닙니다.
# W24 D5 external review 학습 골격
> PDF p806–807의 TEMPLATE와 generic validator를 한 파일에 모았다. 실제 외부 reviewer가 작성한 기록도, 사람 의미 검토 완료 증거도 아니다.
## Review CSV template
id,reviewer_question,category,decision,reason,commit_or_issue
R1,,correctness,accept,,
R2,,scope,reject,,
R3,,reproducibility,defer,,
## 파일·hash 보조 검사
$Artifact = Join-Path $LearnerRoot 'evidence\w24\external-review.csv'
if (!(Test-Path -LiteralPath $Artifact -PathType Leaf)) {
throw "learner artifact missing: $Artifact"
}
$Item = Get-Item -LiteralPath $Artifact
if ($Item.Length -lt 40) {
throw "artifact is too small to support the claim: bytes=$($Item.Length)"
}
$Text = Get-Content -LiteralPath $Artifact -Raw
if ($Text -match '(?i)\b(TODO|TBD|FILL_ME|PLACEHOLDER)\b') {
throw 'unresolved placeholder in learner artifact'
}
$NonBlank = @($Text -split '[\r\n]+' | Where-Object { $_.Trim().Length -gt 0 })
if ($NonBlank.Count -lt 3) {
throw "artifact needs at least three nonblank evidence lines: $($NonBlank.Count)"
}
$Hash = (Get-FileHash -LiteralPath $Artifact -Algorithm SHA256).Hash.ToLowerInvariant()
"LOCAL_ARTIFACT_VALIDATED W24D5 bytes=$($Item.Length) sha256=$Hash"
## 반드시 남는 사람 판정
- 실제 reviewer identity·review 시각·대상 commit을 확인한다.
- 최소 다섯 질문의 decision·reason·commit/issue 연결을 원본과 대조한다.
- LOCAL_ARTIFACT_VALIDATED는 Green이 아니다.
- 서명 전 상태는 HUMAN_SEMANTIC_REVIEW_REQUIRED다.
STEP 06 / 13
코드 한 줄씩 한국어로 번역
비어 있지 않은 31줄을 모두 한국어로 옮깁니다.
비어 있지 않은 원본 줄은 하나도 생략하지 않습니다.
| 줄 | 원본 | 한국어 번역 |
|---|---|---|
| 1 | # W24 D5 external review 학습 골격 | 문서 의미: 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다. |
| 3 | > PDF p806–807의 TEMPLATE와 generic validator를 한 파일에 모았다. 실제 외부 reviewer가 작성한 기록도, 사람 의미 검토 완료 증거도 아니다. | 문서 의미: W24-D5-external-review.md의 다음 검증 또는 설명 단계를 구성한다. |
| 5 | ## Review CSV template | 문서 의미: 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다. |
| 7 | id,reviewer_question,category,decision,reason,commit_or_issue | 문서 의미: W24-D5-external-review.md의 다음 검증 또는 설명 단계를 구성한다. |
| 8 | R1,,correctness,accept,, | 문서 의미: W24-D5-external-review.md의 다음 검증 또는 설명 단계를 구성한다. |
| 9 | R2,,scope,reject,, | 문서 의미: W24-D5-external-review.md의 다음 검증 또는 설명 단계를 구성한다. |
| 10 | R3,,reproducibility,defer,, | 문서 의미: W24-D5-external-review.md의 다음 검증 또는 설명 단계를 구성한다. |
| 12 | ## 파일·hash 보조 검사 | 문서 의미: 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다. |
| 14 | $Artifact = Join-Path $LearnerRoot 'evidence\w24\external-review.csv' | 문서 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 15 | if (!(Test-Path -LiteralPath $Artifact -PathType Leaf)) { | 문서 의미: 필수 파일이나 경로가 실제로 있는지 확인한다. |
| 16 | throw "learner artifact missing: $Artifact" | 문서 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 17 | } | 문서 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 18 | $Item = Get-Item -LiteralPath $Artifact | 문서 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 19 | if ($Item.Length -lt 40) { | 문서 의미: 조건·반복·함수의 실행 block을 연다. |
| 20 | throw "artifact is too small to support the claim: bytes=$($Item.Length)" | 문서 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 21 | } | 문서 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 22 | $Text = Get-Content -LiteralPath $Artifact -Raw | 문서 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 23 | if ($Text -match '(?i)\b(TODO|TBD|FILL_ME|PLACEHOLDER)\b') { | 문서 의미: Markdown 표 또는 PowerShell pipeline에서 값을 열이나 다음 명령으로 연결한다. |
| 24 | throw 'unresolved placeholder in learner artifact' | 문서 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 25 | } | 문서 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 26 | $NonBlank = @($Text -split '[\r\n]+' | Where-Object { $_.Trim().Length -gt 0 }) | 문서 의미: 조건을 만족하는 row만 필터링한다. |
| 27 | if ($NonBlank.Count -lt 3) { | 문서 의미: 조건·반복·함수의 실행 block을 연다. |
| 28 | throw "artifact needs at least three nonblank evidence lines: $($NonBlank.Count)" | 문서 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 29 | } | 문서 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 30 | $Hash = (Get-FileHash -LiteralPath $Artifact -Algorithm SHA256).Hash.ToLowerInvariant() | 문서 의미: 현재 bytes를 64자리 digest로 evidence에 결박한다. |
| 31 | "LOCAL_ARTIFACT_VALIDATED W24D5 bytes=$($Item.Length) sha256=$Hash" | 문서 의미: 파일 bytes·기본 형식·hash만 통과한 보조 marker를 낸다. |
| 33 | ## 반드시 남는 사람 판정 | 문서 의미: 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다. |
| 35 | - 실제 reviewer identity·review 시각·대상 commit을 확인한다. | 문서 의미: W24-D5-external-review.md의 다음 검증 또는 설명 단계를 구성한다. |
| 36 | - 최소 다섯 질문의 decision·reason·commit/issue 연결을 원본과 대조한다. | 문서 의미: W24-D5-external-review.md의 다음 검증 또는 설명 단계를 구성한다. |
| 37 | - LOCAL_ARTIFACT_VALIDATED는 Green이 아니다. | 문서 의미: 파일 bytes·기본 형식·hash만 통과한 보조 marker를 낸다. |
| 38 | - 서명 전 상태는 HUMAN_SEMANTIC_REVIEW_REQUIRED다. | 문서 의미: review·점수·근거의 사실성을 사람이 대조해야 함을 고정한다. |
STEP 07 / 13
기존 수준의 한 줄 읽기·문법 해부
쉬운 설명 다음에 문법과 실행 순서를 정밀하게 읽습니다.
한 줄로 읽기W24 D5 external review — 형식 검사와 사람 의미 검증 분리는 reviewer 질문·decision·reason·commit/issue CSV 골격과 generic bytes/hash 검사를 보여 주고, 행별 사실성은 사람에게 남긴다.
문법 해부
- .md 문법에서 선언·조건·pipeline·block 경계를 먼저 나눈다.
- expected 값과 actual 결과를 같은 이름처럼 보여도 서로 다른 source로 읽는다.
- native exit·row count·hash·사람 판정을 서로 대체하지 않는다.
실행 순서
- 입력 경로·fixture·환경변수·expected 계약을 고정한다.
- source가 실행하는 native process·HTTP·SQL 또는 형식 검사를 따라간다.
- actual 값과 exact marker를 대조하고 실패면 성공 발행 전에 중단한다.
- finally cleanup과 비범위를 evidence에 남긴다.
W24 조각별 정밀 해설
F13-C01 · 원문 1–12줄
- 문법 해부
- .md 문법으로 1–12줄의 선언·조건·pipeline·block을 나눈다.
- 실제 값 추적
- minimum 5 questions, accept/reject/defer, LOCAL_ARTIFACT_VALIDATED를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- expected와 actual이 일치하고 owner evidence가 같은 run/hash에 연결되는 경우다.
- 틀린 예·반례
- 실제 external review가 아니다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- 파일 존재·문자열·hash·exit0 하나를 의미 Green 전체와 같다고 보지 않는다.
- 하지 않는 일
- 실제 external review가 아니다; self-review로 대체하지 않는다; 빈 행 수를 review 품질로 세지 않는다
- 다음 연결
- 다음 조각 또는 F13 evidence 판정으로 상태를 넘긴다.
F13-C02 · 원문 13–24줄
- 문법 해부
- .md 문법으로 13–24줄의 선언·조건·pipeline·block을 나눈다.
- 실제 값 추적
- minimum 5 questions, accept/reject/defer, LOCAL_ARTIFACT_VALIDATED를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- expected와 actual이 일치하고 owner evidence가 같은 run/hash에 연결되는 경우다.
- 틀린 예·반례
- 실제 external review가 아니다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- 파일 존재·문자열·hash·exit0 하나를 의미 Green 전체와 같다고 보지 않는다.
- 하지 않는 일
- 실제 external review가 아니다; self-review로 대체하지 않는다; 빈 행 수를 review 품질로 세지 않는다
- 다음 연결
- 다음 조각 또는 F13 evidence 판정으로 상태를 넘긴다.
F13-C03 · 원문 25–36줄
- 문법 해부
- .md 문법으로 25–36줄의 선언·조건·pipeline·block을 나눈다.
- 실제 값 추적
- minimum 5 questions, accept/reject/defer, LOCAL_ARTIFACT_VALIDATED를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- expected와 actual이 일치하고 owner evidence가 같은 run/hash에 연결되는 경우다.
- 틀린 예·반례
- 실제 external review가 아니다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- 파일 존재·문자열·hash·exit0 하나를 의미 Green 전체와 같다고 보지 않는다.
- 하지 않는 일
- 실제 external review가 아니다; self-review로 대체하지 않는다; 빈 행 수를 review 품질로 세지 않는다
- 다음 연결
- 다음 조각 또는 F13 evidence 판정으로 상태를 넘긴다.
F13-C04 · 원문 37–38줄
- 문법 해부
- .md 문법으로 37–38줄의 선언·조건·pipeline·block을 나눈다.
- 실제 값 추적
- minimum 5 questions, accept/reject/defer, LOCAL_ARTIFACT_VALIDATED를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- expected와 actual이 일치하고 owner evidence가 같은 run/hash에 연결되는 경우다.
- 틀린 예·반례
- 실제 external review가 아니다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- 파일 존재·문자열·hash·exit0 하나를 의미 Green 전체와 같다고 보지 않는다.
- 하지 않는 일
- 실제 external review가 아니다; self-review로 대체하지 않는다; 빈 행 수를 review 품질로 세지 않는다
- 다음 연결
- 다음 조각 또는 F13 evidence 판정으로 상태를 넘긴다.
실행 순서 — W24 D5 external review — 형식 검사와 사람 의미 검증 분리
-
accept/reject/defer가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 reviewer 질문·decision·reason·commit/issue CSV 골격과 generic bytes/hash 검사를 보여 주고, 행별 사실성은 사람에게 남긴다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘self-review로 대체하지 않는다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 accept/reject/defer와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 08 / 13
실제 값 따라가기
같은 입력값이 어느 줄을 지나 어떤 결과가 되는지 추적합니다.
| 순서 | 들어온 값 | 코드가 하는 일 | 나온 값·상태 | 경계 |
|---|---|---|---|---|
| 입력 | minimum 5 questions | source 계약에 대입 | F13 실행/설명 시작 상태 | 실제 external review가 아니다 |
| 검증 | accept/reject/defer | expected와 actual 또는 형식 대조 | 통과 또는 첫 mismatch | self-review로 대체하지 않는다 |
| 증거 | HUMAN_SEMANTIC_REVIEW_REQUIRED | marker·hash·row를 같은 run에 연결 | 범위가 적힌 evidence 후보 | 빈 행 수를 review 품질로 세지 않는다 |
실제 값 — W24 D5 external review — 형식 검사와 사람 의미 검증 분리
-
LOCAL_ARTIFACT_VALIDATED가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 reviewer 질문·decision·reason·commit/issue CSV 골격과 generic bytes/hash 검사를 보여 주고, 행별 사실성은 사람에게 남긴다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘빈 행 수를 review 품질로 세지 않는다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 LOCAL_ARTIFACT_VALIDATED와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 09 / 13
Gradle·PowerShell·HTTP·PostgreSQL 내부에서 벌어지는 일
Gradle·JUnit XML·PowerShell·HTTP·PostgreSQL·Docker에서 실제로 일어나는 일과 증명 범위를 구분합니다.
W24-D5-external-review.md bytes와 expected 값을 읽는다.
파일 존재만으로 runtime 성공은 아니다.native exit·HTTP status·JUnit XML·DB row·hash 중 이 파일이 소유한 값을 만든다.
실제 external review가 아니다관련 evidence와 사람 의미 검토를 release 후보에 연결한다.
빈 행 수를 review 품질로 세지 않는다첫 실패 경계 — W24 D5 external review — 형식 검사와 사람 의미 검증 분리
-
HUMAN_SEMANTIC_REVIEW_REQUIRED가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 reviewer 질문·decision·reason·commit/issue CSV 골격과 generic bytes/hash 검사를 보여 주고, 행별 사실성은 사람에게 남긴다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘실제 external review가 아니다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 HUMAN_SEMANTIC_REVIEW_REQUIRED와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 10 / 13
흔한 착각과 틀린 예
그럴듯하지만 틀린 해석을 반례로 고칩니다.
❌ minimum 5 questions 문자열이 source에 있으니 실제 실행도 Green이다.
왜 틀리나 source literal과 runtime 관찰값은 다른 증거다.
바르게 읽기 native exit·actual XML/HTTP/DB evidence를 별도로 확인한다.
반례 script가 실행 전 경로 오류로 멈춰도 literal은 그대로 남는다.
❌ 파일 SHA-256이 있으면 내용의 의미와 사실성도 검증됐다.
왜 틀리나 hash는 동일 bytes만 말한다.
바르게 읽기 schema·수치·질문·근거는 별도 자동 또는 사람 판정을 거친다.
반례 빈 review 질문을 가진 CSV도 안정된 hash를 가진다.
❌ LOCAL_ARTIFACT_VALIDATED는 release Green과 같다.
왜 틀리나 generic validator는 파일 shape만 확인한다.
바르게 읽기 HUMAN_SEMANTIC_REVIEW_REQUIRED를 유지한다.
반례 잘못된 track 점수표도 byte 수 조건은 통과할 수 있다.
❌ 이 파일이 W24 전체 lifecycle을 모두 소유한다.
왜 틀리나 각 source는 Gate·demo·cleanup·사람 review 중 일부만 담당한다.
바르게 읽기 owner와 non-responsibility를 release manifest에서 분리한다.
반례 D4 source audit에는 runtime_claim=false가 명시된다.
❌ 이전 주 Green이나 오래된 log를 현재 commit 결과로 재사용한다.
왜 틀리나 source·commit·actual result가 같은 실행에 묶이지 않는다.
바르게 읽기 release 후보에서 새 evidence와 hash를 만든다.
반례 expected JSON이 바뀌면 예전 XML은 exact inventory를 증명하지 못한다.
STEP 11 / 13
이 코드가 보장하지 않는 것
이 코드가 책임지지 않는 일을 분리합니다.
실제 external review가 아니다
이 책임을 맡는 곳: runtime Gateself-review로 대체하지 않는다
이 책임을 맡는 곳: external/human review빈 행 수를 review 품질로 세지 않는다
이 책임을 맡는 곳: release manifest실제 external review가 아니다
이 책임을 맡는 곳: 운영 환경증명하지 않는 범위 — W24 D5 external review — 형식 검사와 사람 의미 검증 분리
-
minimum 5 questions가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 reviewer 질문·decision·reason·commit/issue CSV 골격과 generic bytes/hash 검사를 보여 주고, 행별 사실성은 사람에게 남긴다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘self-review로 대체하지 않는다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 minimum 5 questions와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 12 / 13
직접 다시 써보기
뜻 → 조각 → 전체 코드 순서로 다시 씁니다.
1단계 · 뜻부터 복원
- reviewer 질문·decision·reason·commit/issue CSV 골격과 generic bytes/hash 검사를 보여 주고, 행별 사실성은 사람에게 남긴다.
- 핵심 값은 minimum 5 questions, accept/reject/defer, LOCAL_ARTIFACT_VALIDATED, HUMAN_SEMANTIC_REVIEW_REQUIRED다.
2단계 · 코드 조각 재조립
- 1. 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다
- 3. W24-D5-external-review.md의 다음 검증 또는 설명 단계를 구성한다
- 5. 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다
- 7. W24-D5-external-review.md의 다음 검증 또는 설명 단계를 구성한다
- 8. W24-D5-external-review.md의 다음 검증 또는 설명 단계를 구성한다
- 9. W24-D5-external-review.md의 다음 검증 또는 설명 단계를 구성한다
- 10. W24-D5-external-review.md의 다음 검증 또는 설명 단계를 구성한다
- 12. 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다
3단계 · 파일 전체 다시 쓰기
illustrative/markdown/W24-D5-external-review.md을 새 파일에 다시 쓰고 expected·actual·실패·cleanup·비범위를 주석으로 표시한다.
자가 점검
- 비어 있지 않은 모든 source 줄을 한 번씩 읽었나?
- source shape와 runtime Green을 분리했나?
- 사람 검토·외부 상태를 자동 성공으로 꾸미지 않았나?
- 첫 실패와 cleanup 책임을 설명할 수 있나?
STEP 13 / 13
전체 원본 source
감사로 고정한 전체 source를 가감 없이 확인합니다.
학습용 예시 전체 확인하기 · 정본 답안 아님
# W24 D5 external review 학습 골격
> PDF p806–807의 TEMPLATE와 generic validator를 한 파일에 모았다. 실제 외부 reviewer가 작성한 기록도, 사람 의미 검토 완료 증거도 아니다.
## Review CSV template
id,reviewer_question,category,decision,reason,commit_or_issue
R1,,correctness,accept,,
R2,,scope,reject,,
R3,,reproducibility,defer,,
## 파일·hash 보조 검사
$Artifact = Join-Path $LearnerRoot 'evidence\w24\external-review.csv'
if (!(Test-Path -LiteralPath $Artifact -PathType Leaf)) {
throw "learner artifact missing: $Artifact"
}
$Item = Get-Item -LiteralPath $Artifact
if ($Item.Length -lt 40) {
throw "artifact is too small to support the claim: bytes=$($Item.Length)"
}
$Text = Get-Content -LiteralPath $Artifact -Raw
if ($Text -match '(?i)\b(TODO|TBD|FILL_ME|PLACEHOLDER)\b') {
throw 'unresolved placeholder in learner artifact'
}
$NonBlank = @($Text -split '[\r\n]+' | Where-Object { $_.Trim().Length -gt 0 })
if ($NonBlank.Count -lt 3) {
throw "artifact needs at least three nonblank evidence lines: $($NonBlank.Count)"
}
$Hash = (Get-FileHash -LiteralPath $Artifact -Algorithm SHA256).Hash.ToLowerInvariant()
"LOCAL_ARTIFACT_VALIDATED W24D5 bytes=$($Item.Length) sha256=$Hash"
## 반드시 남는 사람 판정
- 실제 reviewer identity·review 시각·대상 commit을 확인한다.
- 최소 다섯 질문의 decision·reason·commit/issue 연결을 원본과 대조한다.
- LOCAL_ARTIFACT_VALIDATED는 Green이 아니다.
- 서명 전 상태는 HUMAN_SEMANTIC_REVIEW_REQUIRED다.
14W24-SQL-Q40 — 상태별 상위 10% 고액 거래
illustrative/sql/W24-SQL-Q40.sql
학습용 예시 · Q39/Q40 prompt 기반 SQL · 정본 답안 아님 · workbook 제공 정답 아님 · 학습용 예시 · 정본 답안 아님 · W24-F1428줄 연결28줄 번역3 chunks
W24-SQL-Q40 — 상태별 상위 10% 고액 거래
illustrative/sql/W24-SQL-Q40.sql
학습용 예시 · Q39/Q40 prompt 기반 SQL · 정본 답안 아님 · workbook 제공 정답 아님 · 학습용 예시 · 정본 답안 아님 · W24-F14STEP 01 / 13
오늘 이 코드에서 해결할 문제
무엇을 이해해야 하는지 질문부터 잡습니다.
status별 PERCENT_RANK를 계산해 고액 상위 후보를 고르고 작은 표본과 cutoff 동률이 결과 cardinality에 미치는 영향을 드러낸다.
- PERCENT_RANK은 어느 source와 실제 결과에서 확인해야 할까?
- 첫 실패를 만드는 조건과 fail-closed 지점은 어디일까?
- 왜 ‘workbook 제공 정답이 아니다’를 별도 경계로 남겨야 할까?
PERCENT_RANKPARTITION BY status<=0.10small sampleties왜 필요한가 — W24-SQL-Q40 — 상태별 상위 10% 고액 거래
-
PERCENT_RANK가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 status별 PERCENT_RANK를 계산해 고액 상위 후보를 고르고 작은 표본과 cutoff 동률이 결과 cardinality에 미치는 영향을 드러낸다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘workbook 제공 정답이 아니다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 PERCENT_RANK와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 02 / 13
아주 짧게: 이 코드는 왜 필요할까?
웹소설 대신 이 코드가 필요한 이유만 두 문단으로 쉽게 봅니다.
새 기능을 멈춘 팀이 코드·test·문서·demo를 같은 release 후보에 묶어 하나씩 검수한다.
검수 도장이 붙은 공통 거래 코어 출고 상자
이 파일은 status별 PERCENT_RANK를 계산해 고액 상위 후보를 고르고 작은 표본과 cutoff 동률이 결과 cardinality에 미치는 영향을 드러낸다. 눈으로 읽을 때는 각 줄을 검수표 한 칸처럼 보고, 입력과 다음 상태를 놓치지 않는다.
마지막 도장은 source shape와 실제 runtime·사람 검토를 구분한 뒤에만 찍는다. 특히 workbook 제공 정답이 아니다
딱 여기까지만 비유는 실행 순서를 돕지만 실제 Gradle·Docker·DB·사람 review를 대신하지 않는다.
STEP 03 / 13
초등학생도 이해하는 설명
생활 비유와 실제 코드의 경계를 함께 확인합니다.
값 1: PERCENT_RANK
이 파일에서 계속 확인할 고정 단서가 PERCENT_RANK다.
- 코드 연결
F14 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- workbook 제공 정답이 아니다
값 2: PARTITION BY status
이 파일에서 계속 확인할 고정 단서가 PARTITION BY status다.
- 코드 연결
F14 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- 정확히 10% 행 수를 보장하지 않는다
값 3: <=0.10
이 파일에서 계속 확인할 고정 단서가 <=0.10다.
- 코드 연결
F14 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- 실제 PostgreSQL 실행 결과가 아니다
값 4: small sample
이 파일에서 계속 확인할 고정 단서가 small sample다.
- 코드 연결
F14 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- workbook 제공 정답이 아니다
값 5: ties
이 파일에서 계속 확인할 고정 단서가 ties다.
- 코드 연결
F14 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- 정확히 10% 행 수를 보장하지 않는다
STEP 04 / 13
비유 ↔ 코드 전체 연결표
감사 규칙상 연결 대상인 원본 28줄을 빠짐없이 연결합니다.
| 줄 | 정확한 원본 줄 | STARRY 비유 | 실제 뜻·입력·결과·한계 |
|---|---|---|---|
| 1줄F14-L01 | -- W24-SQL-Q40 학습용 예시이며 workbook 제공 정답이 아니다. |
출고표 1번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W24-SQL-Q40.sql의 다음 검증 또는 설명 단계를 구성한다.
|
| 2줄F14-L02 | -- 입력 grain: |
출고표 2번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W24-SQL-Q40.sql의 다음 검증 또는 설명 단계를 구성한다.
|
| 3줄F14-L03 | -- PERCENT_RANK는 같은 amount의 동률을 같은 순위로 보존하므로 결과가 정확히 10% 행 수가 아닐 수 있다. |
출고표 3번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 상태 partition 안에서 금액의 상대 순위를 0부터 계산한다.
|
| 4줄F14-L04 | WITH ranked AS ( |
출고표 4번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 SQL 집합의 입력·변환·필터 단계를 선언한다.
|
| 5줄F14-L05 | SELECT |
출고표 5번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 SQL 집합의 입력·변환·필터 단계를 선언한다.
|
| 6줄F14-L06 | tx_id, |
출고표 6번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W24-SQL-Q40.sql의 다음 검증 또는 설명 단계를 구성한다.
|
| 7줄F14-L07 | status, |
출고표 7번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W24-SQL-Q40.sql의 다음 검증 또는 설명 단계를 구성한다.
|
| 8줄F14-L08 | amount, |
출고표 8번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W24-SQL-Q40.sql의 다음 검증 또는 설명 단계를 구성한다.
|
| 9줄F14-L09 | occurred_at, |
출고표 9번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W24-SQL-Q40.sql의 다음 검증 또는 설명 단계를 구성한다.
|
| 10줄F14-L10 | PERCENT_RANK( |
출고표 10번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 상태 partition 안에서 금액의 상대 순위를 0부터 계산한다.
|
| 11줄F14-L11 | PARTITION BY status |
출고표 11번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 각 status를 서로 독립된 window 집합으로 나눈다.
|
| 12줄F14-L12 | ORDER BY amount DESC |
출고표 12번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 출력 또는 window 계산 순서를 안정적으로 정한다.
|
| 13줄F14-L13 | ) AS amount_percent_rank, |
출고표 13번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 상태 partition 안에서 금액의 상대 순위를 0부터 계산한다.
|
| 14줄F14-L14 | COUNT( |
출고표 14번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 각 status를 서로 독립된 window 집합으로 나눈다.
|
| 15줄F14-L15 | FROM business_tx |
출고표 15번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 SQL 집합의 입력·변환·필터 단계를 선언한다.
|
| 16줄F14-L16 | ) |
출고표 16번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 17줄F14-L17 | SELECT |
출고표 17번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 SQL 집합의 입력·변환·필터 단계를 선언한다.
|
| 18줄F14-L18 | tx_id, |
출고표 18번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W24-SQL-Q40.sql의 다음 검증 또는 설명 단계를 구성한다.
|
| 19줄F14-L19 | status, |
출고표 19번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W24-SQL-Q40.sql의 다음 검증 또는 설명 단계를 구성한다.
|
| 20줄F14-L20 | amount, |
출고표 20번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W24-SQL-Q40.sql의 다음 검증 또는 설명 단계를 구성한다.
|
| 21줄F14-L21 | occurred_at, |
출고표 21번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W24-SQL-Q40.sql의 다음 검증 또는 설명 단계를 구성한다.
|
| 22줄F14-L22 | amount_percent_rank, |
출고표 22번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 상태 partition 안에서 금액의 상대 순위를 0부터 계산한다.
|
| 23줄F14-L23 | status_rows |
출고표 23번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W24-SQL-Q40.sql의 다음 검증 또는 설명 단계를 구성한다.
|
| 24줄F14-L24 | FROM ranked |
출고표 24번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 SQL 집합의 입력·변환·필터 단계를 선언한다.
|
| 25줄F14-L25 | WHERE amount_percent_rank <= |
출고표 25번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 상태 partition 안에서 금액의 상대 순위를 0부터 계산한다.
|
| 26줄F14-L26 | ORDER BY status, |
출고표 26번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 출력 또는 window 계산 순서를 안정적으로 정한다.
|
| 28줄F14-L28 | -- 작은 표본 한계: |
출고표 28번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 상태 partition 안에서 금액의 상대 순위를 0부터 계산한다.
|
| 29줄F14-L29 | -- 동률 반례: |
출고표 29번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W24-SQL-Q40.sql의 다음 검증 또는 설명 단계를 구성한다.
|
STEP 05 / 13
원본 코드 조각
원본을 3개 의미 조각으로 나누어 그대로 확인합니다.
파일을 한꺼번에 외우지 않고 실행 의미가 이어지는 작은 조각으로 봅니다. 아래 코드는 prompt·fixture·가정을 밝힌 학습용 예시 source이며, 제공 정본 답안이 아닙니다.
-- W24-SQL-Q40 학습용 예시이며 workbook 제공 정답이 아니다.
-- 입력 grain: business_tx 한 행 = 거래 한 건. 출력 grain: 상태별 상위 10% 후보 거래 한 행.
-- PERCENT_RANK는 같은 amount의 동률을 같은 순위로 보존하므로 결과가 정확히 10% 행 수가 아닐 수 있다.
WITH ranked AS (
SELECT
tx_id,
status,
amount,
occurred_at,
PERCENT_RANK() OVER (
PARTITION BY status
ORDER BY amount DESC
) AS amount_percent_rank,
COUNT(*) OVER (PARTITION BY status) AS status_rows
FROM business_tx
)
SELECT
tx_id,
status,
amount,
occurred_at,
amount_percent_rank,
status_rows
FROM ranked
WHERE amount_percent_rank <= 0.10
ORDER BY status, amount DESC, tx_id;
-- 작은 표본 한계: 상태에 한 행만 있으면 percent_rank=0이라 그 한 행이 포함된다.
-- 동률 반례: cutoff의 같은 amount는 함께 포함되어 한 상태에서 10%보다 많은 행이 나올 수 있다.
STEP 06 / 13
코드 한 줄씩 한국어로 번역
비어 있지 않은 28줄을 모두 한국어로 옮깁니다.
비어 있지 않은 원본 줄은 하나도 생략하지 않습니다.
| 줄 | 원본 | 한국어 번역 |
|---|---|---|
| 1 | -- W24-SQL-Q40 학습용 예시이며 workbook 제공 정답이 아니다. | 실행 의미: W24-SQL-Q40.sql의 다음 검증 또는 설명 단계를 구성한다. |
| 2 | -- 입력 grain: business_tx 한 행 = 거래 한 건. 출력 grain: 상태별 상위 10% 후보 거래 한 행. | 실행 의미: W24-SQL-Q40.sql의 다음 검증 또는 설명 단계를 구성한다. |
| 3 | -- PERCENT_RANK는 같은 amount의 동률을 같은 순위로 보존하므로 결과가 정확히 10% 행 수가 아닐 수 있다. | 실행 의미: 상태 partition 안에서 금액의 상대 순위를 0부터 계산한다. |
| 4 | WITH ranked AS ( | 실행 의미: SQL 집합의 입력·변환·필터 단계를 선언한다. |
| 5 | SELECT | 실행 의미: SQL 집합의 입력·변환·필터 단계를 선언한다. |
| 6 | tx_id, | 실행 의미: W24-SQL-Q40.sql의 다음 검증 또는 설명 단계를 구성한다. |
| 7 | status, | 실행 의미: W24-SQL-Q40.sql의 다음 검증 또는 설명 단계를 구성한다. |
| 8 | amount, | 실행 의미: W24-SQL-Q40.sql의 다음 검증 또는 설명 단계를 구성한다. |
| 9 | occurred_at, | 실행 의미: W24-SQL-Q40.sql의 다음 검증 또는 설명 단계를 구성한다. |
| 10 | PERCENT_RANK() OVER ( | 실행 의미: 상태 partition 안에서 금액의 상대 순위를 0부터 계산한다. |
| 11 | PARTITION BY status | 실행 의미: 각 status를 서로 독립된 window 집합으로 나눈다. |
| 12 | ORDER BY amount DESC | 실행 의미: 출력 또는 window 계산 순서를 안정적으로 정한다. |
| 13 | ) AS amount_percent_rank, | 실행 의미: 상태 partition 안에서 금액의 상대 순위를 0부터 계산한다. |
| 14 | COUNT(*) OVER (PARTITION BY status) AS status_rows | 실행 의미: 각 status를 서로 독립된 window 집합으로 나눈다. |
| 15 | FROM business_tx | 실행 의미: SQL 집합의 입력·변환·필터 단계를 선언한다. |
| 16 | ) | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 17 | SELECT | 실행 의미: SQL 집합의 입력·변환·필터 단계를 선언한다. |
| 18 | tx_id, | 실행 의미: W24-SQL-Q40.sql의 다음 검증 또는 설명 단계를 구성한다. |
| 19 | status, | 실행 의미: W24-SQL-Q40.sql의 다음 검증 또는 설명 단계를 구성한다. |
| 20 | amount, | 실행 의미: W24-SQL-Q40.sql의 다음 검증 또는 설명 단계를 구성한다. |
| 21 | occurred_at, | 실행 의미: W24-SQL-Q40.sql의 다음 검증 또는 설명 단계를 구성한다. |
| 22 | amount_percent_rank, | 실행 의미: 상태 partition 안에서 금액의 상대 순위를 0부터 계산한다. |
| 23 | status_rows | 실행 의미: W24-SQL-Q40.sql의 다음 검증 또는 설명 단계를 구성한다. |
| 24 | FROM ranked | 실행 의미: SQL 집합의 입력·변환·필터 단계를 선언한다. |
| 25 | WHERE amount_percent_rank <= 0.10 | 실행 의미: 상태 partition 안에서 금액의 상대 순위를 0부터 계산한다. |
| 26 | ORDER BY status, amount DESC, tx_id; | 실행 의미: 출력 또는 window 계산 순서를 안정적으로 정한다. |
| 28 | -- 작은 표본 한계: 상태에 한 행만 있으면 percent_rank=0이라 그 한 행이 포함된다. | 실행 의미: 상태 partition 안에서 금액의 상대 순위를 0부터 계산한다. |
| 29 | -- 동률 반례: cutoff의 같은 amount는 함께 포함되어 한 상태에서 10%보다 많은 행이 나올 수 있다. | 실행 의미: W24-SQL-Q40.sql의 다음 검증 또는 설명 단계를 구성한다. |
STEP 07 / 13
기존 수준의 한 줄 읽기·문법 해부
쉬운 설명 다음에 문법과 실행 순서를 정밀하게 읽습니다.
한 줄로 읽기W24-SQL-Q40 — 상태별 상위 10% 고액 거래는 status별 PERCENT_RANK를 계산해 고액 상위 후보를 고르고 작은 표본과 cutoff 동률이 결과 cardinality에 미치는 영향을 드러낸다.
문법 해부
- .sql 문법에서 선언·조건·pipeline·block 경계를 먼저 나눈다.
- expected 값과 actual 결과를 같은 이름처럼 보여도 서로 다른 source로 읽는다.
- native exit·row count·hash·사람 판정을 서로 대체하지 않는다.
실행 순서
- 입력 경로·fixture·환경변수·expected 계약을 고정한다.
- source가 실행하는 native process·HTTP·SQL 또는 형식 검사를 따라간다.
- actual 값과 exact marker를 대조하고 실패면 성공 발행 전에 중단한다.
- finally cleanup과 비범위를 evidence에 남긴다.
W24 조각별 정밀 해설
F14-C01 · 원문 1–12줄
- 문법 해부
- .sql 문법으로 1–12줄의 선언·조건·pipeline·block을 나눈다.
- 실제 값 추적
- PERCENT_RANK, PARTITION BY status, <=0.10를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- expected와 actual이 일치하고 owner evidence가 같은 run/hash에 연결되는 경우다.
- 틀린 예·반례
- workbook 제공 정답이 아니다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- 파일 존재·문자열·hash·exit0 하나를 의미 Green 전체와 같다고 보지 않는다.
- 하지 않는 일
- workbook 제공 정답이 아니다; 정확히 10% 행 수를 보장하지 않는다; 실제 PostgreSQL 실행 결과가 아니다
- 다음 연결
- 다음 조각 또는 F14 evidence 판정으로 상태를 넘긴다.
F14-C02 · 원문 13–24줄
- 문법 해부
- .sql 문법으로 13–24줄의 선언·조건·pipeline·block을 나눈다.
- 실제 값 추적
- PERCENT_RANK, PARTITION BY status, <=0.10를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- expected와 actual이 일치하고 owner evidence가 같은 run/hash에 연결되는 경우다.
- 틀린 예·반례
- workbook 제공 정답이 아니다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- 파일 존재·문자열·hash·exit0 하나를 의미 Green 전체와 같다고 보지 않는다.
- 하지 않는 일
- workbook 제공 정답이 아니다; 정확히 10% 행 수를 보장하지 않는다; 실제 PostgreSQL 실행 결과가 아니다
- 다음 연결
- 다음 조각 또는 F14 evidence 판정으로 상태를 넘긴다.
F14-C03 · 원문 25–29줄
- 문법 해부
- .sql 문법으로 25–29줄의 선언·조건·pipeline·block을 나눈다.
- 실제 값 추적
- PERCENT_RANK, PARTITION BY status, <=0.10를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- expected와 actual이 일치하고 owner evidence가 같은 run/hash에 연결되는 경우다.
- 틀린 예·반례
- workbook 제공 정답이 아니다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- 파일 존재·문자열·hash·exit0 하나를 의미 Green 전체와 같다고 보지 않는다.
- 하지 않는 일
- workbook 제공 정답이 아니다; 정확히 10% 행 수를 보장하지 않는다; 실제 PostgreSQL 실행 결과가 아니다
- 다음 연결
- 다음 조각 또는 F14 evidence 판정으로 상태를 넘긴다.
실행 순서 — W24-SQL-Q40 — 상태별 상위 10% 고액 거래
-
PARTITION BY status가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 status별 PERCENT_RANK를 계산해 고액 상위 후보를 고르고 작은 표본과 cutoff 동률이 결과 cardinality에 미치는 영향을 드러낸다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘정확히 10% 행 수를 보장하지 않는다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 PARTITION BY status와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 08 / 13
실제 값 따라가기
같은 입력값이 어느 줄을 지나 어떤 결과가 되는지 추적합니다.
| 순서 | 들어온 값 | 코드가 하는 일 | 나온 값·상태 | 경계 |
|---|---|---|---|---|
| 입력 | PERCENT_RANK | source 계약에 대입 | F14 실행/설명 시작 상태 | workbook 제공 정답이 아니다 |
| 검증 | PARTITION BY status | expected와 actual 또는 형식 대조 | 통과 또는 첫 mismatch | 정확히 10% 행 수를 보장하지 않는다 |
| 증거 | ties | marker·hash·row를 같은 run에 연결 | 범위가 적힌 evidence 후보 | 실제 PostgreSQL 실행 결과가 아니다 |
실제 값 — W24-SQL-Q40 — 상태별 상위 10% 고액 거래
-
<=0.10가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 status별 PERCENT_RANK를 계산해 고액 상위 후보를 고르고 작은 표본과 cutoff 동률이 결과 cardinality에 미치는 영향을 드러낸다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘실제 PostgreSQL 실행 결과가 아니다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 <=0.10와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 09 / 13
Gradle·PowerShell·HTTP·PostgreSQL 내부에서 벌어지는 일
Gradle·JUnit XML·PowerShell·HTTP·PostgreSQL·Docker에서 실제로 일어나는 일과 증명 범위를 구분합니다.
W24-SQL-Q40.sql bytes와 expected 값을 읽는다.
파일 존재만으로 runtime 성공은 아니다.native exit·HTTP status·JUnit XML·DB row·hash 중 이 파일이 소유한 값을 만든다.
workbook 제공 정답이 아니다관련 evidence와 사람 의미 검토를 release 후보에 연결한다.
실제 PostgreSQL 실행 결과가 아니다첫 실패 경계 — W24-SQL-Q40 — 상태별 상위 10% 고액 거래
-
small sample가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 status별 PERCENT_RANK를 계산해 고액 상위 후보를 고르고 작은 표본과 cutoff 동률이 결과 cardinality에 미치는 영향을 드러낸다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘workbook 제공 정답이 아니다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 small sample와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 10 / 13
흔한 착각과 틀린 예
그럴듯하지만 틀린 해석을 반례로 고칩니다.
❌ PERCENT_RANK 문자열이 source에 있으니 실제 실행도 Green이다.
왜 틀리나 source literal과 runtime 관찰값은 다른 증거다.
바르게 읽기 native exit·actual XML/HTTP/DB evidence를 별도로 확인한다.
반례 script가 실행 전 경로 오류로 멈춰도 literal은 그대로 남는다.
❌ 파일 SHA-256이 있으면 내용의 의미와 사실성도 검증됐다.
왜 틀리나 hash는 동일 bytes만 말한다.
바르게 읽기 schema·수치·질문·근거는 별도 자동 또는 사람 판정을 거친다.
반례 빈 review 질문을 가진 CSV도 안정된 hash를 가진다.
❌ LOCAL_ARTIFACT_VALIDATED는 release Green과 같다.
왜 틀리나 generic validator는 파일 shape만 확인한다.
바르게 읽기 HUMAN_SEMANTIC_REVIEW_REQUIRED를 유지한다.
반례 잘못된 track 점수표도 byte 수 조건은 통과할 수 있다.
❌ 이 파일이 W24 전체 lifecycle을 모두 소유한다.
왜 틀리나 각 source는 Gate·demo·cleanup·사람 review 중 일부만 담당한다.
바르게 읽기 owner와 non-responsibility를 release manifest에서 분리한다.
반례 D4 source audit에는 runtime_claim=false가 명시된다.
❌ 이전 주 Green이나 오래된 log를 현재 commit 결과로 재사용한다.
왜 틀리나 source·commit·actual result가 같은 실행에 묶이지 않는다.
바르게 읽기 release 후보에서 새 evidence와 hash를 만든다.
반례 expected JSON이 바뀌면 예전 XML은 exact inventory를 증명하지 못한다.
STEP 11 / 13
이 코드가 보장하지 않는 것
이 코드가 책임지지 않는 일을 분리합니다.
workbook 제공 정답이 아니다
이 책임을 맡는 곳: runtime Gate정확히 10% 행 수를 보장하지 않는다
이 책임을 맡는 곳: external/human review실제 PostgreSQL 실행 결과가 아니다
이 책임을 맡는 곳: release manifestworkbook 제공 정답이 아니다
이 책임을 맡는 곳: 운영 환경증명하지 않는 범위 — W24-SQL-Q40 — 상태별 상위 10% 고액 거래
-
ties가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 status별 PERCENT_RANK를 계산해 고액 상위 후보를 고르고 작은 표본과 cutoff 동률이 결과 cardinality에 미치는 영향을 드러낸다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘정확히 10% 행 수를 보장하지 않는다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 ties와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 12 / 13
직접 다시 써보기
뜻 → 조각 → 전체 코드 순서로 다시 씁니다.
1단계 · 뜻부터 복원
- status별 PERCENT_RANK를 계산해 고액 상위 후보를 고르고 작은 표본과 cutoff 동률이 결과 cardinality에 미치는 영향을 드러낸다.
- 핵심 값은 PERCENT_RANK, PARTITION BY status, <=0.10, small sample, ties다.
2단계 · 코드 조각 재조립
- 1. W24-SQL-Q40.sql의 다음 검증 또는 설명 단계를 구성한다
- 2. W24-SQL-Q40.sql의 다음 검증 또는 설명 단계를 구성한다
- 3. 상태 partition 안에서 금액의 상대 순위를 0부터 계산한다
- 4. SQL 집합의 입력·변환·필터 단계를 선언한다
- 5. SQL 집합의 입력·변환·필터 단계를 선언한다
- 6. W24-SQL-Q40.sql의 다음 검증 또는 설명 단계를 구성한다
- 7. W24-SQL-Q40.sql의 다음 검증 또는 설명 단계를 구성한다
- 8. W24-SQL-Q40.sql의 다음 검증 또는 설명 단계를 구성한다
3단계 · 파일 전체 다시 쓰기
illustrative/sql/W24-SQL-Q40.sql을 새 파일에 다시 쓰고 expected·actual·실패·cleanup·비범위를 주석으로 표시한다.
자가 점검
- 비어 있지 않은 모든 source 줄을 한 번씩 읽었나?
- source shape와 runtime Green을 분리했나?
- 사람 검토·외부 상태를 자동 성공으로 꾸미지 않았나?
- 첫 실패와 cleanup 책임을 설명할 수 있나?
STEP 13 / 13
전체 원본 source
감사로 고정한 전체 source를 가감 없이 확인합니다.
학습용 예시 전체 확인하기 · 정본 답안 아님
-- W24-SQL-Q40 학습용 예시이며 workbook 제공 정답이 아니다.
-- 입력 grain: business_tx 한 행 = 거래 한 건. 출력 grain: 상태별 상위 10% 후보 거래 한 행.
-- PERCENT_RANK는 같은 amount의 동률을 같은 순위로 보존하므로 결과가 정확히 10% 행 수가 아닐 수 있다.
WITH ranked AS (
SELECT
tx_id,
status,
amount,
occurred_at,
PERCENT_RANK() OVER (
PARTITION BY status
ORDER BY amount DESC
) AS amount_percent_rank,
COUNT(*) OVER (PARTITION BY status) AS status_rows
FROM business_tx
)
SELECT
tx_id,
status,
amount,
occurred_at,
amount_percent_rank,
status_rows
FROM ranked
WHERE amount_percent_rank <= 0.10
ORDER BY status, amount DESC, tx_id;
-- 작은 표본 한계: 상태에 한 행만 있으면 percent_rank=0이라 그 한 행이 포함된다.
-- 동률 반례: cutoff의 같은 amount는 함께 포함되어 한 상태에서 10%보다 많은 행이 나올 수 있다.
15W24 D6 track selection — 가중치 100과 정확히 한 track
illustrative/markdown/W24-D6-track-selection.md
학습용 예시 · PDF template/validator · 정본 답안 아님 · 학습용 예시 · 정본 답안 아님 · W24-F1534줄 연결34줄 번역4 chunks
W24 D6 track selection — 가중치 100과 정확히 한 track
illustrative/markdown/W24-D6-track-selection.md
학습용 예시 · PDF template/validator · 정본 답안 아님 · 학습용 예시 · 정본 답안 아님 · W24-F15STEP 01 / 13
오늘 이 코드에서 해결할 문제
무엇을 이해해야 하는지 질문부터 잡습니다.
job fit·관심·자료·팀 기회·완주 위험을 40·20·15·15·10으로 비교하고 근거·합계·단일 선택을 사람 검토에 남긴다.
- weights=100은 어느 source와 실제 결과에서 확인해야 할까?
- 첫 실패를 만드는 조건과 fail-closed 지점은 어디일까?
- 왜 ‘실제 점수·URL·서명이 비어 있다’를 별도 경계로 남겨야 할까?
weights=100securitiescardevidence URLsingle selection왜 필요한가 — W24 D6 track selection — 가중치 100과 정확히 한 track
-
weights=100가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 job fit·관심·자료·팀 기회·완주 위험을 40·20·15·15·10으로 비교하고 근거·합계·단일 선택을 사람 검토에 남긴다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘실제 점수·URL·서명이 비어 있다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 weights=100와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 02 / 13
아주 짧게: 이 코드는 왜 필요할까?
웹소설 대신 이 코드가 필요한 이유만 두 문단으로 쉽게 봅니다.
새 기능을 멈춘 팀이 코드·test·문서·demo를 같은 release 후보에 묶어 하나씩 검수한다.
검수 도장이 붙은 공통 거래 코어 출고 상자
이 파일은 job fit·관심·자료·팀 기회·완주 위험을 40·20·15·15·10으로 비교하고 근거·합계·단일 선택을 사람 검토에 남긴다. 눈으로 읽을 때는 각 줄을 검수표 한 칸처럼 보고, 입력과 다음 상태를 놓치지 않는다.
마지막 도장은 source shape와 실제 runtime·사람 검토를 구분한 뒤에만 찍는다. 특히 실제 점수·URL·서명이 비어 있다
딱 여기까지만 비유는 실행 순서를 돕지만 실제 Gradle·Docker·DB·사람 review를 대신하지 않는다.
STEP 03 / 13
초등학생도 이해하는 설명
생활 비유와 실제 코드의 경계를 함께 확인합니다.
값 1: weights=100
이 파일에서 계속 확인할 고정 단서가 weights=100다.
- 코드 연결
F15 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- 실제 점수·URL·서명이 비어 있다
값 2: securities
이 파일에서 계속 확인할 고정 단서가 securities다.
- 코드 연결
F15 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- generic hash 검사는 선택 완료가 아니다
값 3: card
이 파일에서 계속 확인할 고정 단서가 card다.
- 코드 연결
F15 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- 두 track 동시 선택을 허용하지 않는다
값 4: evidence URL
이 파일에서 계속 확인할 고정 단서가 evidence URL다.
- 코드 연결
F15 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- 실제 점수·URL·서명이 비어 있다
값 5: single selection
이 파일에서 계속 확인할 고정 단서가 single selection다.
- 코드 연결
F15 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- generic hash 검사는 선택 완료가 아니다
STEP 04 / 13
비유 ↔ 코드 전체 연결표
감사 규칙상 연결 대상인 원본 34줄을 빠짐없이 연결합니다.
| 줄 | 정확한 원본 줄 | STARRY 비유 | 실제 뜻·입력·결과·한계 |
|---|---|---|---|
| 1줄F15-L01 | # W24 D6 track selection 학습 골격 |
출고표 1번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다.
|
| 3줄F15-L03 | > PDF p810–811의 TEMPLATE와 generic validator를 한 파일에 모았다. |
출고표 3번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W24-D6-track-selection.md의 다음 검증 또는 설명 단계를 구성한다.
|
| 5줄F15-L05 | ## Selection CSV template |
출고표 5번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다.
|
| 7줄F15-L07 | criterion, |
출고표 7번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W24-D6-track-selection.md의 다음 검증 또는 설명 단계를 구성한다.
|
| 8줄F15-L08 | job_fit, |
출고표 8번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W24-D6-track-selection.md의 다음 검증 또는 설명 단계를 구성한다.
|
| 9줄F15-L09 | interest, |
출고표 9번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W24-D6-track-selection.md의 다음 검증 또는 설명 단계를 구성한다.
|
| 10줄F15-L10 | source_quality, |
출고표 10번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W24-D6-track-selection.md의 다음 검증 또는 설명 단계를 구성한다.
|
| 11줄F15-L11 | team_opportunity, |
출고표 11번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W24-D6-track-selection.md의 다음 검증 또는 설명 단계를 구성한다.
|
| 12줄F15-L12 | completion_risk, |
출고표 12번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W24-D6-track-selection.md의 다음 검증 또는 설명 단계를 구성한다.
|
| 14줄F15-L14 | ## 파일·hash 보조 검사 |
출고표 14번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다.
|
| 16줄F15-L16 | $Artifact = |
출고표 16번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 17줄F15-L17 | if ( |
출고표 17번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 필수 파일이나 경로가 실제로 있는지 확인한다.
|
| 18줄F15-L18 | throw "learner artifact missing: |
출고표 18번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 19줄F15-L19 | } |
출고표 19번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 20줄F15-L20 | $Item = |
출고표 20번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 21줄F15-L21 | if ( |
출고표 21번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 조건·반복·함수의 실행 block을 연다.
|
| 22줄F15-L22 | throw "artifact is too small to support the claim: |
출고표 22번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 23줄F15-L23 | } |
출고표 23번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 24줄F15-L24 | $Text = |
출고표 24번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 25줄F15-L25 | if ( |
출고표 25번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 Markdown 표 또는 PowerShell pipeline에서 값을 열이나 다음 명령으로 연결한다.
|
| 26줄F15-L26 | throw 'unresolved placeholder in learner artifact' |
출고표 26번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 27줄F15-L27 | } |
출고표 27번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 28줄F15-L28 | $NonBlank = |
출고표 28번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 조건을 만족하는 row만 필터링한다.
|
| 29줄F15-L29 | if ( |
출고표 29번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 조건·반복·함수의 실행 block을 연다.
|
| 30줄F15-L30 | throw "artifact needs at least three nonblank evidence lines: |
출고표 30번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 31줄F15-L31 | } |
출고표 31번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 32줄F15-L32 | $Hash = |
출고표 32번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 현재 bytes를 64자리 digest로 evidence에 결박한다.
|
| 33줄F15-L33 | "LOCAL_ARTIFACT_VALIDATED W24D6 bytes= |
출고표 33번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 파일 bytes·기본 형식·hash만 통과한 보조 marker를 낸다.
|
| 35줄F15-L35 | ## 반드시 남는 사람 판정 |
출고표 35번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다.
|
| 37줄F15-L37 | - weight는 40+ |
출고표 37번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W24-D6-track-selection.md의 다음 검증 또는 설명 단계를 구성한다.
|
| 38줄F15-L38 | - 각 점수의 실제 근거 URL과 확인일을 사람이 대조한다. |
출고표 38번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W24-D6-track-selection.md의 다음 검증 또는 설명 단계를 구성한다.
|
| 39줄F15-L39 | - 가중 합계와 사전 정의 tie-breaker를 다시 계산한다. |
출고표 39번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W24-D6-track-selection.md의 다음 검증 또는 설명 단계를 구성한다.
|
| 40줄F15-L40 | - 증권 또는 카드 정확히 하나만 선택하고 서명한다. |
출고표 40번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W24-D6-track-selection.md의 다음 검증 또는 설명 단계를 구성한다.
|
| 41줄F15-L41 | - LOCAL_ARTIFACT_VALIDATED 뒤에도 HUMAN_SEMANTIC_REVIEW_REQUIRED다. |
출고표 41번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 파일 bytes·기본 형식·hash만 통과한 보조 marker를 낸다.
|
STEP 05 / 13
원본 코드 조각
원본을 4개 의미 조각으로 나누어 그대로 확인합니다.
파일을 한꺼번에 외우지 않고 실행 의미가 이어지는 작은 조각으로 봅니다. 아래 코드는 prompt·fixture·가정을 밝힌 학습용 예시 source이며, 제공 정본 답안이 아닙니다.
# W24 D6 track selection 학습 골격
> PDF p810–811의 TEMPLATE와 generic validator를 한 파일에 모았다. 실제 점수·근거 URL·서명·최종 선택은 비어 있다.
## Selection CSV template
criterion,weight,securities,card,evidence
job_fit,40,,,
interest,20,,,
source_quality,15,,,
team_opportunity,15,,,
completion_risk,10,,,
## 파일·hash 보조 검사
$Artifact = Join-Path $LearnerRoot 'evidence\w24\track-selection.csv'
if (!(Test-Path -LiteralPath $Artifact -PathType Leaf)) {
throw "learner artifact missing: $Artifact"
}
$Item = Get-Item -LiteralPath $Artifact
if ($Item.Length -lt 40) {
throw "artifact is too small to support the claim: bytes=$($Item.Length)"
}
$Text = Get-Content -LiteralPath $Artifact -Raw
if ($Text -match '(?i)\b(TODO|TBD|FILL_ME|PLACEHOLDER)\b') {
throw 'unresolved placeholder in learner artifact'
}
$NonBlank = @($Text -split '[\r\n]+' | Where-Object { $_.Trim().Length -gt 0 })
if ($NonBlank.Count -lt 3) {
throw "artifact needs at least three nonblank evidence lines: $($NonBlank.Count)"
}
$Hash = (Get-FileHash -LiteralPath $Artifact -Algorithm SHA256).Hash.ToLowerInvariant()
"LOCAL_ARTIFACT_VALIDATED W24D6 bytes=$($Item.Length) sha256=$Hash"
## 반드시 남는 사람 판정
- weight는 40+20+15+15+10=100이어야 한다.
- 각 점수의 실제 근거 URL과 확인일을 사람이 대조한다.
- 가중 합계와 사전 정의 tie-breaker를 다시 계산한다.
- 증권 또는 카드 정확히 하나만 선택하고 서명한다.
- LOCAL_ARTIFACT_VALIDATED 뒤에도 HUMAN_SEMANTIC_REVIEW_REQUIRED다.
STEP 06 / 13
코드 한 줄씩 한국어로 번역
비어 있지 않은 34줄을 모두 한국어로 옮깁니다.
비어 있지 않은 원본 줄은 하나도 생략하지 않습니다.
| 줄 | 원본 | 한국어 번역 |
|---|---|---|
| 1 | # W24 D6 track selection 학습 골격 | 문서 의미: 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다. |
| 3 | > PDF p810–811의 TEMPLATE와 generic validator를 한 파일에 모았다. 실제 점수·근거 URL·서명·최종 선택은 비어 있다. | 문서 의미: W24-D6-track-selection.md의 다음 검증 또는 설명 단계를 구성한다. |
| 5 | ## Selection CSV template | 문서 의미: 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다. |
| 7 | criterion,weight,securities,card,evidence | 문서 의미: W24-D6-track-selection.md의 다음 검증 또는 설명 단계를 구성한다. |
| 8 | job_fit,40,,, | 문서 의미: W24-D6-track-selection.md의 다음 검증 또는 설명 단계를 구성한다. |
| 9 | interest,20,,, | 문서 의미: W24-D6-track-selection.md의 다음 검증 또는 설명 단계를 구성한다. |
| 10 | source_quality,15,,, | 문서 의미: W24-D6-track-selection.md의 다음 검증 또는 설명 단계를 구성한다. |
| 11 | team_opportunity,15,,, | 문서 의미: W24-D6-track-selection.md의 다음 검증 또는 설명 단계를 구성한다. |
| 12 | completion_risk,10,,, | 문서 의미: W24-D6-track-selection.md의 다음 검증 또는 설명 단계를 구성한다. |
| 14 | ## 파일·hash 보조 검사 | 문서 의미: 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다. |
| 16 | $Artifact = Join-Path $LearnerRoot 'evidence\w24\track-selection.csv' | 문서 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 17 | if (!(Test-Path -LiteralPath $Artifact -PathType Leaf)) { | 문서 의미: 필수 파일이나 경로가 실제로 있는지 확인한다. |
| 18 | throw "learner artifact missing: $Artifact" | 문서 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 19 | } | 문서 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 20 | $Item = Get-Item -LiteralPath $Artifact | 문서 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 21 | if ($Item.Length -lt 40) { | 문서 의미: 조건·반복·함수의 실행 block을 연다. |
| 22 | throw "artifact is too small to support the claim: bytes=$($Item.Length)" | 문서 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 23 | } | 문서 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 24 | $Text = Get-Content -LiteralPath $Artifact -Raw | 문서 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 25 | if ($Text -match '(?i)\b(TODO|TBD|FILL_ME|PLACEHOLDER)\b') { | 문서 의미: Markdown 표 또는 PowerShell pipeline에서 값을 열이나 다음 명령으로 연결한다. |
| 26 | throw 'unresolved placeholder in learner artifact' | 문서 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 27 | } | 문서 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 28 | $NonBlank = @($Text -split '[\r\n]+' | Where-Object { $_.Trim().Length -gt 0 }) | 문서 의미: 조건을 만족하는 row만 필터링한다. |
| 29 | if ($NonBlank.Count -lt 3) { | 문서 의미: 조건·반복·함수의 실행 block을 연다. |
| 30 | throw "artifact needs at least three nonblank evidence lines: $($NonBlank.Count)" | 문서 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 31 | } | 문서 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 32 | $Hash = (Get-FileHash -LiteralPath $Artifact -Algorithm SHA256).Hash.ToLowerInvariant() | 문서 의미: 현재 bytes를 64자리 digest로 evidence에 결박한다. |
| 33 | "LOCAL_ARTIFACT_VALIDATED W24D6 bytes=$($Item.Length) sha256=$Hash" | 문서 의미: 파일 bytes·기본 형식·hash만 통과한 보조 marker를 낸다. |
| 35 | ## 반드시 남는 사람 판정 | 문서 의미: 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다. |
| 37 | - weight는 40+20+15+15+10=100이어야 한다. | 문서 의미: W24-D6-track-selection.md의 다음 검증 또는 설명 단계를 구성한다. |
| 38 | - 각 점수의 실제 근거 URL과 확인일을 사람이 대조한다. | 문서 의미: W24-D6-track-selection.md의 다음 검증 또는 설명 단계를 구성한다. |
| 39 | - 가중 합계와 사전 정의 tie-breaker를 다시 계산한다. | 문서 의미: W24-D6-track-selection.md의 다음 검증 또는 설명 단계를 구성한다. |
| 40 | - 증권 또는 카드 정확히 하나만 선택하고 서명한다. | 문서 의미: W24-D6-track-selection.md의 다음 검증 또는 설명 단계를 구성한다. |
| 41 | - LOCAL_ARTIFACT_VALIDATED 뒤에도 HUMAN_SEMANTIC_REVIEW_REQUIRED다. | 문서 의미: 파일 bytes·기본 형식·hash만 통과한 보조 marker를 낸다. |
STEP 07 / 13
기존 수준의 한 줄 읽기·문법 해부
쉬운 설명 다음에 문법과 실행 순서를 정밀하게 읽습니다.
한 줄로 읽기W24 D6 track selection — 가중치 100과 정확히 한 track는 job fit·관심·자료·팀 기회·완주 위험을 40·20·15·15·10으로 비교하고 근거·합계·단일 선택을 사람 검토에 남긴다.
문법 해부
- .md 문법에서 선언·조건·pipeline·block 경계를 먼저 나눈다.
- expected 값과 actual 결과를 같은 이름처럼 보여도 서로 다른 source로 읽는다.
- native exit·row count·hash·사람 판정을 서로 대체하지 않는다.
실행 순서
- 입력 경로·fixture·환경변수·expected 계약을 고정한다.
- source가 실행하는 native process·HTTP·SQL 또는 형식 검사를 따라간다.
- actual 값과 exact marker를 대조하고 실패면 성공 발행 전에 중단한다.
- finally cleanup과 비범위를 evidence에 남긴다.
W24 조각별 정밀 해설
F15-C01 · 원문 1–12줄
- 문법 해부
- .md 문법으로 1–12줄의 선언·조건·pipeline·block을 나눈다.
- 실제 값 추적
- weights=100, securities, card를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- expected와 actual이 일치하고 owner evidence가 같은 run/hash에 연결되는 경우다.
- 틀린 예·반례
- 실제 점수·URL·서명이 비어 있다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- 파일 존재·문자열·hash·exit0 하나를 의미 Green 전체와 같다고 보지 않는다.
- 하지 않는 일
- 실제 점수·URL·서명이 비어 있다; generic hash 검사는 선택 완료가 아니다; 두 track 동시 선택을 허용하지 않는다
- 다음 연결
- 다음 조각 또는 F15 evidence 판정으로 상태를 넘긴다.
F15-C02 · 원문 13–24줄
- 문법 해부
- .md 문법으로 13–24줄의 선언·조건·pipeline·block을 나눈다.
- 실제 값 추적
- weights=100, securities, card를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- expected와 actual이 일치하고 owner evidence가 같은 run/hash에 연결되는 경우다.
- 틀린 예·반례
- 실제 점수·URL·서명이 비어 있다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- 파일 존재·문자열·hash·exit0 하나를 의미 Green 전체와 같다고 보지 않는다.
- 하지 않는 일
- 실제 점수·URL·서명이 비어 있다; generic hash 검사는 선택 완료가 아니다; 두 track 동시 선택을 허용하지 않는다
- 다음 연결
- 다음 조각 또는 F15 evidence 판정으로 상태를 넘긴다.
F15-C03 · 원문 25–36줄
- 문법 해부
- .md 문법으로 25–36줄의 선언·조건·pipeline·block을 나눈다.
- 실제 값 추적
- weights=100, securities, card를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- expected와 actual이 일치하고 owner evidence가 같은 run/hash에 연결되는 경우다.
- 틀린 예·반례
- 실제 점수·URL·서명이 비어 있다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- 파일 존재·문자열·hash·exit0 하나를 의미 Green 전체와 같다고 보지 않는다.
- 하지 않는 일
- 실제 점수·URL·서명이 비어 있다; generic hash 검사는 선택 완료가 아니다; 두 track 동시 선택을 허용하지 않는다
- 다음 연결
- 다음 조각 또는 F15 evidence 판정으로 상태를 넘긴다.
F15-C04 · 원문 37–41줄
- 문법 해부
- .md 문법으로 37–41줄의 선언·조건·pipeline·block을 나눈다.
- 실제 값 추적
- weights=100, securities, card를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- expected와 actual이 일치하고 owner evidence가 같은 run/hash에 연결되는 경우다.
- 틀린 예·반례
- 실제 점수·URL·서명이 비어 있다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- 파일 존재·문자열·hash·exit0 하나를 의미 Green 전체와 같다고 보지 않는다.
- 하지 않는 일
- 실제 점수·URL·서명이 비어 있다; generic hash 검사는 선택 완료가 아니다; 두 track 동시 선택을 허용하지 않는다
- 다음 연결
- 다음 조각 또는 F15 evidence 판정으로 상태를 넘긴다.
실행 순서 — W24 D6 track selection — 가중치 100과 정확히 한 track
-
securities가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 job fit·관심·자료·팀 기회·완주 위험을 40·20·15·15·10으로 비교하고 근거·합계·단일 선택을 사람 검토에 남긴다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘generic hash 검사는 선택 완료가 아니다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 securities와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 08 / 13
실제 값 따라가기
같은 입력값이 어느 줄을 지나 어떤 결과가 되는지 추적합니다.
| 순서 | 들어온 값 | 코드가 하는 일 | 나온 값·상태 | 경계 |
|---|---|---|---|---|
| 입력 | weights=100 | source 계약에 대입 | F15 실행/설명 시작 상태 | 실제 점수·URL·서명이 비어 있다 |
| 검증 | securities | expected와 actual 또는 형식 대조 | 통과 또는 첫 mismatch | generic hash 검사는 선택 완료가 아니다 |
| 증거 | single selection | marker·hash·row를 같은 run에 연결 | 범위가 적힌 evidence 후보 | 두 track 동시 선택을 허용하지 않는다 |
실제 값 — W24 D6 track selection — 가중치 100과 정확히 한 track
-
card가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 job fit·관심·자료·팀 기회·완주 위험을 40·20·15·15·10으로 비교하고 근거·합계·단일 선택을 사람 검토에 남긴다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘두 track 동시 선택을 허용하지 않는다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 card와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 09 / 13
Gradle·PowerShell·HTTP·PostgreSQL 내부에서 벌어지는 일
Gradle·JUnit XML·PowerShell·HTTP·PostgreSQL·Docker에서 실제로 일어나는 일과 증명 범위를 구분합니다.
W24-D6-track-selection.md bytes와 expected 값을 읽는다.
파일 존재만으로 runtime 성공은 아니다.native exit·HTTP status·JUnit XML·DB row·hash 중 이 파일이 소유한 값을 만든다.
실제 점수·URL·서명이 비어 있다관련 evidence와 사람 의미 검토를 release 후보에 연결한다.
두 track 동시 선택을 허용하지 않는다첫 실패 경계 — W24 D6 track selection — 가중치 100과 정확히 한 track
-
evidence URL가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 job fit·관심·자료·팀 기회·완주 위험을 40·20·15·15·10으로 비교하고 근거·합계·단일 선택을 사람 검토에 남긴다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘실제 점수·URL·서명이 비어 있다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 evidence URL와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 10 / 13
흔한 착각과 틀린 예
그럴듯하지만 틀린 해석을 반례로 고칩니다.
❌ weights=100 문자열이 source에 있으니 실제 실행도 Green이다.
왜 틀리나 source literal과 runtime 관찰값은 다른 증거다.
바르게 읽기 native exit·actual XML/HTTP/DB evidence를 별도로 확인한다.
반례 script가 실행 전 경로 오류로 멈춰도 literal은 그대로 남는다.
❌ 파일 SHA-256이 있으면 내용의 의미와 사실성도 검증됐다.
왜 틀리나 hash는 동일 bytes만 말한다.
바르게 읽기 schema·수치·질문·근거는 별도 자동 또는 사람 판정을 거친다.
반례 빈 review 질문을 가진 CSV도 안정된 hash를 가진다.
❌ LOCAL_ARTIFACT_VALIDATED는 release Green과 같다.
왜 틀리나 generic validator는 파일 shape만 확인한다.
바르게 읽기 HUMAN_SEMANTIC_REVIEW_REQUIRED를 유지한다.
반례 잘못된 track 점수표도 byte 수 조건은 통과할 수 있다.
❌ 이 파일이 W24 전체 lifecycle을 모두 소유한다.
왜 틀리나 각 source는 Gate·demo·cleanup·사람 review 중 일부만 담당한다.
바르게 읽기 owner와 non-responsibility를 release manifest에서 분리한다.
반례 D4 source audit에는 runtime_claim=false가 명시된다.
❌ 이전 주 Green이나 오래된 log를 현재 commit 결과로 재사용한다.
왜 틀리나 source·commit·actual result가 같은 실행에 묶이지 않는다.
바르게 읽기 release 후보에서 새 evidence와 hash를 만든다.
반례 expected JSON이 바뀌면 예전 XML은 exact inventory를 증명하지 못한다.
STEP 11 / 13
이 코드가 보장하지 않는 것
이 코드가 책임지지 않는 일을 분리합니다.
실제 점수·URL·서명이 비어 있다
이 책임을 맡는 곳: runtime Gategeneric hash 검사는 선택 완료가 아니다
이 책임을 맡는 곳: external/human review두 track 동시 선택을 허용하지 않는다
이 책임을 맡는 곳: release manifest실제 점수·URL·서명이 비어 있다
이 책임을 맡는 곳: 운영 환경증명하지 않는 범위 — W24 D6 track selection — 가중치 100과 정확히 한 track
-
single selection가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 job fit·관심·자료·팀 기회·완주 위험을 40·20·15·15·10으로 비교하고 근거·합계·단일 선택을 사람 검토에 남긴다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘generic hash 검사는 선택 완료가 아니다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 single selection와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 12 / 13
직접 다시 써보기
뜻 → 조각 → 전체 코드 순서로 다시 씁니다.
1단계 · 뜻부터 복원
- job fit·관심·자료·팀 기회·완주 위험을 40·20·15·15·10으로 비교하고 근거·합계·단일 선택을 사람 검토에 남긴다.
- 핵심 값은 weights=100, securities, card, evidence URL, single selection다.
2단계 · 코드 조각 재조립
- 1. 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다
- 3. W24-D6-track-selection.md의 다음 검증 또는 설명 단계를 구성한다
- 5. 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다
- 7. W24-D6-track-selection.md의 다음 검증 또는 설명 단계를 구성한다
- 8. W24-D6-track-selection.md의 다음 검증 또는 설명 단계를 구성한다
- 9. W24-D6-track-selection.md의 다음 검증 또는 설명 단계를 구성한다
- 10. W24-D6-track-selection.md의 다음 검증 또는 설명 단계를 구성한다
- 11. W24-D6-track-selection.md의 다음 검증 또는 설명 단계를 구성한다
3단계 · 파일 전체 다시 쓰기
illustrative/markdown/W24-D6-track-selection.md을 새 파일에 다시 쓰고 expected·actual·실패·cleanup·비범위를 주석으로 표시한다.
자가 점검
- 비어 있지 않은 모든 source 줄을 한 번씩 읽었나?
- source shape와 runtime Green을 분리했나?
- 사람 검토·외부 상태를 자동 성공으로 꾸미지 않았나?
- 첫 실패와 cleanup 책임을 설명할 수 있나?
STEP 13 / 13
전체 원본 source
감사로 고정한 전체 source를 가감 없이 확인합니다.
학습용 예시 전체 확인하기 · 정본 답안 아님
# W24 D6 track selection 학습 골격
> PDF p810–811의 TEMPLATE와 generic validator를 한 파일에 모았다. 실제 점수·근거 URL·서명·최종 선택은 비어 있다.
## Selection CSV template
criterion,weight,securities,card,evidence
job_fit,40,,,
interest,20,,,
source_quality,15,,,
team_opportunity,15,,,
completion_risk,10,,,
## 파일·hash 보조 검사
$Artifact = Join-Path $LearnerRoot 'evidence\w24\track-selection.csv'
if (!(Test-Path -LiteralPath $Artifact -PathType Leaf)) {
throw "learner artifact missing: $Artifact"
}
$Item = Get-Item -LiteralPath $Artifact
if ($Item.Length -lt 40) {
throw "artifact is too small to support the claim: bytes=$($Item.Length)"
}
$Text = Get-Content -LiteralPath $Artifact -Raw
if ($Text -match '(?i)\b(TODO|TBD|FILL_ME|PLACEHOLDER)\b') {
throw 'unresolved placeholder in learner artifact'
}
$NonBlank = @($Text -split '[\r\n]+' | Where-Object { $_.Trim().Length -gt 0 })
if ($NonBlank.Count -lt 3) {
throw "artifact needs at least three nonblank evidence lines: $($NonBlank.Count)"
}
$Hash = (Get-FileHash -LiteralPath $Artifact -Algorithm SHA256).Hash.ToLowerInvariant()
"LOCAL_ARTIFACT_VALIDATED W24D6 bytes=$($Item.Length) sha256=$Hash"
## 반드시 남는 사람 판정
- weight는 40+20+15+15+10=100이어야 한다.
- 각 점수의 실제 근거 URL과 확인일을 사람이 대조한다.
- 가중 합계와 사전 정의 tie-breaker를 다시 계산한다.
- 증권 또는 카드 정확히 하나만 선택하고 서명한다.
- LOCAL_ARTIFACT_VALIDATED 뒤에도 HUMAN_SEMANTIC_REVIEW_REQUIRED다.
16run-w24-release.ps1 — exact Gate와 lifecycle을 묶는 release owner
scripts/run-w24-release.ps1
PDF 전문 정본 · packaged PowerShell source · 정본 · W24-F1615줄 연결15줄 번역2 chunks
run-w24-release.ps1 — exact Gate와 lifecycle을 묶는 release owner
scripts/run-w24-release.ps1
PDF 전문 정본 · packaged PowerShell source · 정본 · W24-F16STEP 01 / 13
오늘 이 코드에서 해결할 문제
무엇을 이해해야 하는지 질문부터 잡습니다.
clean test와 coreV1Gate actual XML 37/66을 다시 계산한 뒤 lifecycle runner를 호출하고 release marker를 발행한다.
- classes=37은 어느 source와 실제 결과에서 확인해야 할까?
- 첫 실패를 만드는 조건과 fail-closed 지점은 어디일까?
- 왜 ‘tag 생성 자체는 이 script에 없다’를 별도 경계로 남겨야 할까?
classes=37selectors=43tests=66core_gate=GREENdemo=GREENcleanup=1왜 필요한가 — run-w24-release.ps1 — exact Gate와 lifecycle을 묶는 release owner
-
classes=37가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 clean test와 coreV1Gate actual XML 37/66을 다시 계산한 뒤 lifecycle runner를 호출하고 release marker를 발행한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘tag 생성 자체는 이 script에 없다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 classes=37와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 02 / 13
아주 짧게: 이 코드는 왜 필요할까?
웹소설 대신 이 코드가 필요한 이유만 두 문단으로 쉽게 봅니다.
새 기능을 멈춘 팀이 코드·test·문서·demo를 같은 release 후보에 묶어 하나씩 검수한다.
검수 도장이 붙은 공통 거래 코어 출고 상자
이 파일은 clean test와 coreV1Gate actual XML 37/66을 다시 계산한 뒤 lifecycle runner를 호출하고 release marker를 발행한다. 눈으로 읽을 때는 각 줄을 검수표 한 칸처럼 보고, 입력과 다음 상태를 놓치지 않는다.
마지막 도장은 source shape와 실제 runtime·사람 검토를 구분한 뒤에만 찍는다. 특히 tag 생성 자체는 이 script에 없다
딱 여기까지만 비유는 실행 순서를 돕지만 실제 Gradle·Docker·DB·사람 review를 대신하지 않는다.
STEP 03 / 13
초등학생도 이해하는 설명
생활 비유와 실제 코드의 경계를 함께 확인합니다.
값 1: classes=37
이 파일에서 계속 확인할 고정 단서가 classes=37다.
- 코드 연결
F16 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- tag 생성 자체는 이 script에 없다
값 2: selectors=43
이 파일에서 계속 확인할 고정 단서가 selectors=43다.
- 코드 연결
F16 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- Git clean·track 한 개는 별도 사람 Gate다
값 3: tests=66
이 파일에서 계속 확인할 고정 단서가 tests=66다.
- 코드 연결
F16 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- 실행하지 않은 HTML에서 Green을 주장하지 않는다
값 4: core_gate=GREEN
이 파일에서 계속 확인할 고정 단서가 core_gate=GREEN다.
- 코드 연결
F16 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- tag 생성 자체는 이 script에 없다
값 5: demo=GREEN
이 파일에서 계속 확인할 고정 단서가 demo=GREEN다.
- 코드 연결
F16 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- Git clean·track 한 개는 별도 사람 Gate다
STEP 04 / 13
비유 ↔ 코드 전체 연결표
감사 규칙상 연결 대상인 원본 15줄을 빠짐없이 연결합니다.
| 줄 | 정확한 원본 줄 | STARRY 비유 | 실제 뜻·입력·결과·한계 |
|---|---|---|---|
| 1줄F16-L01 | param( |
출고표 1번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 PowerShell script가 받을 입력 계약을 연다.
|
| 2줄F16-L02 | $ErrorActionPreference= |
출고표 2번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 PowerShell 오류를 계속 진행하지 않고 중단시키는 기본 정책을 둔다.
|
| 3줄F16-L03 | Push-Location $learner |
출고표 3번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 run-w24-release.ps1의 다음 검증 또는 설명 단계를 구성한다.
|
| 4줄F16-L04 | try{ |
출고표 4번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 조건·반복·함수의 실행 block을 연다.
|
| 5줄F16-L05 | & . |
출고표 5번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 learner project의 Gradle wrapper로 지정 task를 실행한다.
|
| 6줄F16-L06 | if( |
출고표 6번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 native process 종료 코드를 검사해 실패를 놓치지 않는다.
|
| 7줄F16-L07 | $contract= |
출고표 7번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 class 이름과 기대 test 수를 exact inventory로 고정한다.
|
| 8줄F16-L08 | $rows= |
출고표 8번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 JUnit XML 결과 파일만 exact inventory 입력으로 모은다.
|
| 9줄F16-L09 | $actual= |
출고표 9번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 expected와 actual 집합에 누락·예상 밖 항목이 있는지 비교한다.
|
| 10줄F16-L10 | if( |
출고표 10번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 class 이름과 기대 test 수를 exact inventory로 고정한다.
|
| 11줄F16-L11 | $rows|ConvertTo-Json|Set-Content -Encoding utf8 ( |
출고표 11번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 검증된 object를 JSON evidence text로 직렬화한다.
|
| 12줄F16-L12 | }finally{ |
출고표 12번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 중간 실패가 있어도 반드시 실행할 cleanup 경계를 연다.
|
| 13줄F16-L13 | & powershell. |
출고표 13번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 run-w24-release.ps1의 다음 검증 또는 설명 단계를 구성한다.
|
| 14줄F16-L14 | if( |
출고표 14번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 native process 종료 코드를 검사해 실패를 놓치지 않는다.
|
| 15줄F16-L15 | "W24_RELEASE_GREEN classes= |
출고표 15번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 selector 총수를 JSON 계약에 고정한다.
|
STEP 05 / 13
원본 코드 조각
원본을 2개 의미 조각으로 나누어 그대로 확인합니다.
파일을 한꺼번에 외우지 않고 실행 의미가 이어지는 작은 조각으로 봅니다. 아래 코드는 hash로 고정한 native 정본 source에서 그대로 잘랐습니다.
param([Parameter(Mandatory=$true)][string]$ProjectRoot,[Parameter(Mandatory=$true)][string]$EvidenceDir,[string]$ComposeProject='w24-learner-release',[int]$Port=28080,[int]$DbPort=62440)
$ErrorActionPreference='Stop';$learner=(Resolve-Path -LiteralPath $ProjectRoot).Path;$e=[IO.Path]::GetFullPath($EvidenceDir);New-Item -ItemType Directory -Force $e|Out-Null
Push-Location $learner
try{
& .\gradlew.bat clean test coreV1Gate --no-daemon
if($LASTEXITCODE-ne 0){throw "W24 coreV1Gate exit=$LASTEXITCODE"}
$contract=Get-Content -Raw -LiteralPath (Join-Path (Split-Path -Parent $PSScriptRoot) 'learning_stages/w24/overlay/core-v1-expected.json')|ConvertFrom-Json;$expected=@($contract.classes.psobject.Properties.Name)
$rows=@(Get-ChildItem build/test-results/coreV1Gate -Filter 'TEST-*.xml'|ForEach-Object{[xml]$x=Get-Content -Raw $_.FullName;[pscustomobject]@{class=[string]$x.testsuite.name;tests=[int]$x.testsuite.tests;failures=[int]$x.testsuite.failures;errors=[int]$x.testsuite.errors;skipped=[int]$x.testsuite.skipped}})
$actual=@($rows.class|Sort-Object -Unique);if(Compare-Object ($expected|Sort-Object) $actual){throw "W24 exact class inventory mismatch expected=$expected actual=$actual"}
if($rows.Count-ne 37-or@($rows|Where-Object{$_.tests-ne[int]$contract.classes.psobject.Properties[$_.class].Value-or$_.failures-ne 0-or$_.errors-ne 0-or$_.skipped-ne 0}).Count-ne 0){throw "W24 per-suite XML exact mismatch classes=$($rows.Count)"};$total=($rows|Measure-Object tests -Sum).Sum;if($total-ne 66){throw "W24 exact test total mismatch=$total"}
$rows|ConvertTo-Json|Set-Content -Encoding utf8 (Join-Path $e 'core-v1-gate.json')
}finally{Pop-Location}
& powershell.exe -NoProfile -ExecutionPolicy Bypass -File (Join-Path $PSScriptRoot 'run-w24-lifecycle.ps1') -ProjectRoot $learner -EvidenceDir $e -ComposeProject $ComposeProject -Port $Port -DbPort $DbPort
if($LASTEXITCODE-ne 0){throw "W24 lifecycle exit=$LASTEXITCODE"}
"W24_RELEASE_GREEN classes=37 selectors=43 tests=66 core_gate=GREEN demo=GREEN cleanup=1 native_exit=0"
STEP 06 / 13
코드 한 줄씩 한국어로 번역
비어 있지 않은 15줄을 모두 한국어로 옮깁니다.
비어 있지 않은 원본 줄은 하나도 생략하지 않습니다.
| 줄 | 원본 | 한국어 번역 |
|---|---|---|
| 1 | param([Parameter(Mandatory=$true)][string]$ProjectRoot,[Parameter(Mandatory=$true)][string]$EvidenceDir,[string]$ComposeProject='w24-learner-release',[int]$Port=28080,[int]$DbPort=62440) | 실행 의미: PowerShell script가 받을 입력 계약을 연다. |
| 2 | $ErrorActionPreference='Stop';$learner=(Resolve-Path -LiteralPath $ProjectRoot).Path;$e=[IO.Path]::GetFullPath($EvidenceDir);New-Item -ItemType Directory -Force $e|Out-Null | 실행 의미: PowerShell 오류를 계속 진행하지 않고 중단시키는 기본 정책을 둔다. |
| 3 | Push-Location $learner | 실행 의미: run-w24-release.ps1의 다음 검증 또는 설명 단계를 구성한다. |
| 4 | try{ | 실행 의미: 조건·반복·함수의 실행 block을 연다. |
| 5 | & .\gradlew.bat clean test coreV1Gate --no-daemon | 실행 의미: learner project의 Gradle wrapper로 지정 task를 실행한다. |
| 6 | if($LASTEXITCODE-ne 0){throw "W24 coreV1Gate exit=$LASTEXITCODE"} | 실행 의미: native process 종료 코드를 검사해 실패를 놓치지 않는다. |
| 7 | $contract=Get-Content -Raw -LiteralPath (Join-Path (Split-Path -Parent $PSScriptRoot) 'learning_stages/w24/overlay/core-v1-expected.json')|ConvertFrom-Json;$expected=@($contract.classes.psobject.Properties.Name) | 실행 의미: class 이름과 기대 test 수를 exact inventory로 고정한다. |
| 8 | $rows=@(Get-ChildItem build/test-results/coreV1Gate -Filter 'TEST-*.xml'|ForEach-Object{[xml]$x=Get-Content -Raw $_.FullName;[pscustomobject]@{class=[string]$x.testsuite.name;tests=[int]$x.testsuite.tests;failures=[int]$x.testsuite.failures;errors=[int]$x.testsuite.errors;skipped=[int]$x.testsuite.skipped}}) | 실행 의미: JUnit XML 결과 파일만 exact inventory 입력으로 모은다. |
| 9 | $actual=@($rows.class|Sort-Object -Unique);if(Compare-Object ($expected|Sort-Object) $actual){throw "W24 exact class inventory mismatch expected=$expected actual=$actual"} | 실행 의미: expected와 actual 집합에 누락·예상 밖 항목이 있는지 비교한다. |
| 10 | if($rows.Count-ne 37-or@($rows|Where-Object{$_.tests-ne[int]$contract.classes.psobject.Properties[$_.class].Value-or$_.failures-ne 0-or$_.errors-ne 0-or$_.skipped-ne 0}).Count-ne 0){throw "W24 per-suite XML exact mismatch classes=$($rows.Count)"};$total=($rows|Measure-Object tests -Sum).Sum;if($total-ne 66){throw "W24 exact test total mismatch=$total"} | 실행 의미: class 이름과 기대 test 수를 exact inventory로 고정한다. |
| 11 | $rows|ConvertTo-Json|Set-Content -Encoding utf8 (Join-Path $e 'core-v1-gate.json') | 실행 의미: 검증된 object를 JSON evidence text로 직렬화한다. |
| 12 | }finally{Pop-Location} | 실행 의미: 중간 실패가 있어도 반드시 실행할 cleanup 경계를 연다. |
| 13 | & powershell.exe -NoProfile -ExecutionPolicy Bypass -File (Join-Path $PSScriptRoot 'run-w24-lifecycle.ps1') -ProjectRoot $learner -EvidenceDir $e -ComposeProject $ComposeProject -Port $Port -DbPort $DbPort | 실행 의미: run-w24-release.ps1의 다음 검증 또는 설명 단계를 구성한다. |
| 14 | if($LASTEXITCODE-ne 0){throw "W24 lifecycle exit=$LASTEXITCODE"} | 실행 의미: native process 종료 코드를 검사해 실패를 놓치지 않는다. |
| 15 | "W24_RELEASE_GREEN classes=37 selectors=43 tests=66 core_gate=GREEN demo=GREEN cleanup=1 native_exit=0" | 실행 의미: selector 총수를 JSON 계약에 고정한다. |
STEP 07 / 13
기존 수준의 한 줄 읽기·문법 해부
쉬운 설명 다음에 문법과 실행 순서를 정밀하게 읽습니다.
한 줄로 읽기run-w24-release.ps1 — exact Gate와 lifecycle을 묶는 release owner는 clean test와 coreV1Gate actual XML 37/66을 다시 계산한 뒤 lifecycle runner를 호출하고 release marker를 발행한다.
문법 해부
- .ps1 문법에서 선언·조건·pipeline·block 경계를 먼저 나눈다.
- expected 값과 actual 결과를 같은 이름처럼 보여도 서로 다른 source로 읽는다.
- native exit·row count·hash·사람 판정을 서로 대체하지 않는다.
실행 순서
- 입력 경로·fixture·환경변수·expected 계약을 고정한다.
- source가 실행하는 native process·HTTP·SQL 또는 형식 검사를 따라간다.
- actual 값과 exact marker를 대조하고 실패면 성공 발행 전에 중단한다.
- finally cleanup과 비범위를 evidence에 남긴다.
W24 조각별 정밀 해설
F16-C01 · 원문 1–12줄
- 문법 해부
- .ps1 문법으로 1–12줄의 선언·조건·pipeline·block을 나눈다.
- 실제 값 추적
- classes=37, selectors=43, tests=66를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- expected와 actual이 일치하고 owner evidence가 같은 run/hash에 연결되는 경우다.
- 틀린 예·반례
- tag 생성 자체는 이 script에 없다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- 파일 존재·문자열·hash·exit0 하나를 의미 Green 전체와 같다고 보지 않는다.
- 하지 않는 일
- tag 생성 자체는 이 script에 없다; Git clean·track 한 개는 별도 사람 Gate다; 실행하지 않은 HTML에서 Green을 주장하지 않는다
- 다음 연결
- 다음 조각 또는 F16 evidence 판정으로 상태를 넘긴다.
F16-C02 · 원문 13–15줄
- 문법 해부
- .ps1 문법으로 13–15줄의 선언·조건·pipeline·block을 나눈다.
- 실제 값 추적
- classes=37, selectors=43, tests=66를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- expected와 actual이 일치하고 owner evidence가 같은 run/hash에 연결되는 경우다.
- 틀린 예·반례
- tag 생성 자체는 이 script에 없다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- 파일 존재·문자열·hash·exit0 하나를 의미 Green 전체와 같다고 보지 않는다.
- 하지 않는 일
- tag 생성 자체는 이 script에 없다; Git clean·track 한 개는 별도 사람 Gate다; 실행하지 않은 HTML에서 Green을 주장하지 않는다
- 다음 연결
- 다음 조각 또는 F16 evidence 판정으로 상태를 넘긴다.
실행 순서 — run-w24-release.ps1 — exact Gate와 lifecycle을 묶는 release owner
-
selectors=43가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 clean test와 coreV1Gate actual XML 37/66을 다시 계산한 뒤 lifecycle runner를 호출하고 release marker를 발행한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘Git clean·track 한 개는 별도 사람 Gate다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 selectors=43와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 08 / 13
실제 값 따라가기
같은 입력값이 어느 줄을 지나 어떤 결과가 되는지 추적합니다.
| 순서 | 들어온 값 | 코드가 하는 일 | 나온 값·상태 | 경계 |
|---|---|---|---|---|
| 입력 | classes=37 | source 계약에 대입 | F16 실행/설명 시작 상태 | tag 생성 자체는 이 script에 없다 |
| 검증 | selectors=43 | expected와 actual 또는 형식 대조 | 통과 또는 첫 mismatch | Git clean·track 한 개는 별도 사람 Gate다 |
| 증거 | cleanup=1 | marker·hash·row를 같은 run에 연결 | 범위가 적힌 evidence 후보 | 실행하지 않은 HTML에서 Green을 주장하지 않는다 |
실제 값 — run-w24-release.ps1 — exact Gate와 lifecycle을 묶는 release owner
-
tests=66가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 clean test와 coreV1Gate actual XML 37/66을 다시 계산한 뒤 lifecycle runner를 호출하고 release marker를 발행한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘실행하지 않은 HTML에서 Green을 주장하지 않는다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 tests=66와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 09 / 13
Gradle·PowerShell·HTTP·PostgreSQL 내부에서 벌어지는 일
Gradle·JUnit XML·PowerShell·HTTP·PostgreSQL·Docker에서 실제로 일어나는 일과 증명 범위를 구분합니다.
run-w24-release.ps1 bytes와 expected 값을 읽는다.
파일 존재만으로 runtime 성공은 아니다.native exit·HTTP status·JUnit XML·DB row·hash 중 이 파일이 소유한 값을 만든다.
tag 생성 자체는 이 script에 없다관련 evidence와 사람 의미 검토를 release 후보에 연결한다.
실행하지 않은 HTML에서 Green을 주장하지 않는다첫 실패 경계 — run-w24-release.ps1 — exact Gate와 lifecycle을 묶는 release owner
-
core_gate=GREEN가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 clean test와 coreV1Gate actual XML 37/66을 다시 계산한 뒤 lifecycle runner를 호출하고 release marker를 발행한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘tag 생성 자체는 이 script에 없다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 core_gate=GREEN와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 10 / 13
흔한 착각과 틀린 예
그럴듯하지만 틀린 해석을 반례로 고칩니다.
❌ classes=37 문자열이 source에 있으니 실제 실행도 Green이다.
왜 틀리나 source literal과 runtime 관찰값은 다른 증거다.
바르게 읽기 native exit·actual XML/HTTP/DB evidence를 별도로 확인한다.
반례 script가 실행 전 경로 오류로 멈춰도 literal은 그대로 남는다.
❌ 파일 SHA-256이 있으면 내용의 의미와 사실성도 검증됐다.
왜 틀리나 hash는 동일 bytes만 말한다.
바르게 읽기 schema·수치·질문·근거는 별도 자동 또는 사람 판정을 거친다.
반례 빈 review 질문을 가진 CSV도 안정된 hash를 가진다.
❌ LOCAL_ARTIFACT_VALIDATED는 release Green과 같다.
왜 틀리나 generic validator는 파일 shape만 확인한다.
바르게 읽기 HUMAN_SEMANTIC_REVIEW_REQUIRED를 유지한다.
반례 잘못된 track 점수표도 byte 수 조건은 통과할 수 있다.
❌ 이 파일이 W24 전체 lifecycle을 모두 소유한다.
왜 틀리나 각 source는 Gate·demo·cleanup·사람 review 중 일부만 담당한다.
바르게 읽기 owner와 non-responsibility를 release manifest에서 분리한다.
반례 D4 source audit에는 runtime_claim=false가 명시된다.
❌ 이전 주 Green이나 오래된 log를 현재 commit 결과로 재사용한다.
왜 틀리나 source·commit·actual result가 같은 실행에 묶이지 않는다.
바르게 읽기 release 후보에서 새 evidence와 hash를 만든다.
반례 expected JSON이 바뀌면 예전 XML은 exact inventory를 증명하지 못한다.
STEP 11 / 13
이 코드가 보장하지 않는 것
이 코드가 책임지지 않는 일을 분리합니다.
tag 생성 자체는 이 script에 없다
이 책임을 맡는 곳: runtime GateGit clean·track 한 개는 별도 사람 Gate다
이 책임을 맡는 곳: external/human review실행하지 않은 HTML에서 Green을 주장하지 않는다
이 책임을 맡는 곳: release manifesttag 생성 자체는 이 script에 없다
이 책임을 맡는 곳: 운영 환경증명하지 않는 범위 — run-w24-release.ps1 — exact Gate와 lifecycle을 묶는 release owner
-
demo=GREEN가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 clean test와 coreV1Gate actual XML 37/66을 다시 계산한 뒤 lifecycle runner를 호출하고 release marker를 발행한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘Git clean·track 한 개는 별도 사람 Gate다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 demo=GREEN와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 12 / 13
직접 다시 써보기
뜻 → 조각 → 전체 코드 순서로 다시 씁니다.
1단계 · 뜻부터 복원
- clean test와 coreV1Gate actual XML 37/66을 다시 계산한 뒤 lifecycle runner를 호출하고 release marker를 발행한다.
- 핵심 값은 classes=37, selectors=43, tests=66, core_gate=GREEN, demo=GREEN, cleanup=1다.
2단계 · 코드 조각 재조립
- 1. PowerShell script가 받을 입력 계약을 연다
- 2. PowerShell 오류를 계속 진행하지 않고 중단시키는 기본 정책을 둔다
- 3. run-w24-release.ps1의 다음 검증 또는 설명 단계를 구성한다
- 4. 조건·반복·함수의 실행 block을 연다
- 5. learner project의 Gradle wrapper로 지정 task를 실행한다
- 6. native process 종료 코드를 검사해 실패를 놓치지 않는다
- 7. class 이름과 기대 test 수를 exact inventory로 고정한다
- 8. JUnit XML 결과 파일만 exact inventory 입력으로 모은다
3단계 · 파일 전체 다시 쓰기
scripts/run-w24-release.ps1을 새 파일에 다시 쓰고 expected·actual·실패·cleanup·비범위를 주석으로 표시한다.
자가 점검
- 비어 있지 않은 모든 source 줄을 한 번씩 읽었나?
- source shape와 runtime Green을 분리했나?
- 사람 검토·외부 상태를 자동 성공으로 꾸미지 않았나?
- 첫 실패와 cleanup 책임을 설명할 수 있나?
STEP 13 / 13
전체 원본 source
감사로 고정한 전체 source를 가감 없이 확인합니다.
원문 정본 전체 source 확인하기
param([Parameter(Mandatory=$true)][string]$ProjectRoot,[Parameter(Mandatory=$true)][string]$EvidenceDir,[string]$ComposeProject='w24-learner-release',[int]$Port=28080,[int]$DbPort=62440)
$ErrorActionPreference='Stop';$learner=(Resolve-Path -LiteralPath $ProjectRoot).Path;$e=[IO.Path]::GetFullPath($EvidenceDir);New-Item -ItemType Directory -Force $e|Out-Null
Push-Location $learner
try{
& .\gradlew.bat clean test coreV1Gate --no-daemon
if($LASTEXITCODE-ne 0){throw "W24 coreV1Gate exit=$LASTEXITCODE"}
$contract=Get-Content -Raw -LiteralPath (Join-Path (Split-Path -Parent $PSScriptRoot) 'learning_stages/w24/overlay/core-v1-expected.json')|ConvertFrom-Json;$expected=@($contract.classes.psobject.Properties.Name)
$rows=@(Get-ChildItem build/test-results/coreV1Gate -Filter 'TEST-*.xml'|ForEach-Object{[xml]$x=Get-Content -Raw $_.FullName;[pscustomobject]@{class=[string]$x.testsuite.name;tests=[int]$x.testsuite.tests;failures=[int]$x.testsuite.failures;errors=[int]$x.testsuite.errors;skipped=[int]$x.testsuite.skipped}})
$actual=@($rows.class|Sort-Object -Unique);if(Compare-Object ($expected|Sort-Object) $actual){throw "W24 exact class inventory mismatch expected=$expected actual=$actual"}
if($rows.Count-ne 37-or@($rows|Where-Object{$_.tests-ne[int]$contract.classes.psobject.Properties[$_.class].Value-or$_.failures-ne 0-or$_.errors-ne 0-or$_.skipped-ne 0}).Count-ne 0){throw "W24 per-suite XML exact mismatch classes=$($rows.Count)"};$total=($rows|Measure-Object tests -Sum).Sum;if($total-ne 66){throw "W24 exact test total mismatch=$total"}
$rows|ConvertTo-Json|Set-Content -Encoding utf8 (Join-Path $e 'core-v1-gate.json')
}finally{Pop-Location}
& powershell.exe -NoProfile -ExecutionPolicy Bypass -File (Join-Path $PSScriptRoot 'run-w24-lifecycle.ps1') -ProjectRoot $learner -EvidenceDir $e -ComposeProject $ComposeProject -Port $Port -DbPort $DbPort
if($LASTEXITCODE-ne 0){throw "W24 lifecycle exit=$LASTEXITCODE"}
"W24_RELEASE_GREEN classes=37 selectors=43 tests=66 core_gate=GREEN demo=GREEN cleanup=1 native_exit=0"
17run-w24-lifecycle.ps1 — DB·host JVM·demo·cleanup 책임
scripts/run-w24-lifecycle.ps1
PDF 전문 정본 · packaged PowerShell source · 정본 · W24-F1725줄 연결25줄 번역3 chunks
run-w24-lifecycle.ps1 — DB·host JVM·demo·cleanup 책임
scripts/run-w24-lifecycle.ps1
PDF 전문 정본 · packaged PowerShell source · 정본 · W24-F17STEP 01 / 13
오늘 이 코드에서 해결할 문제
무엇을 이해해야 하는지 질문부터 잡습니다.
disposable DB Compose와 host JVM을 띄워 readiness와 demo를 확인하고 성공·실패 모두에서 process·container·volume·secret 환경변수를 정리한다.
- port=28080은 어느 source와 실제 결과에서 확인해야 할까?
- 첫 실패를 만드는 조건과 fail-closed 지점은 어디일까?
- 왜 ‘Docker·port·자격증명이 필요하다’를 별도 경계로 남겨야 할까?
port=28080dbPort=62440health=UPcleanup=1container_absentvolume_absent왜 필요한가 — run-w24-lifecycle.ps1 — DB·host JVM·demo·cleanup 책임
-
port=28080가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 disposable DB Compose와 host JVM을 띄워 readiness와 demo를 확인하고 성공·실패 모두에서 process·container·volume·secret 환경변수를 정리한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘Docker·port·자격증명이 필요하다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 port=28080와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 02 / 13
아주 짧게: 이 코드는 왜 필요할까?
웹소설 대신 이 코드가 필요한 이유만 두 문단으로 쉽게 봅니다.
새 기능을 멈춘 팀이 코드·test·문서·demo를 같은 release 후보에 묶어 하나씩 검수한다.
검수 도장이 붙은 공통 거래 코어 출고 상자
이 파일은 disposable DB Compose와 host JVM을 띄워 readiness와 demo를 확인하고 성공·실패 모두에서 process·container·volume·secret 환경변수를 정리한다. 눈으로 읽을 때는 각 줄을 검수표 한 칸처럼 보고, 입력과 다음 상태를 놓치지 않는다.
마지막 도장은 source shape와 실제 runtime·사람 검토를 구분한 뒤에만 찍는다. 특히 Docker·port·자격증명이 필요하다
딱 여기까지만 비유는 실행 순서를 돕지만 실제 Gradle·Docker·DB·사람 review를 대신하지 않는다.
STEP 03 / 13
초등학생도 이해하는 설명
생활 비유와 실제 코드의 경계를 함께 확인합니다.
값 1: port=28080
이 파일에서 계속 확인할 고정 단서가 port=28080다.
- 코드 연결
F17 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- Docker·port·자격증명이 필요하다
값 2: dbPort=62440
이 파일에서 계속 확인할 고정 단서가 dbPort=62440다.
- 코드 연결
F17 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- 강제 실패 경로도 cleanup 책임을 유지한다
값 3: health=UP
이 파일에서 계속 확인할 고정 단서가 health=UP다.
- 코드 연결
F17 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- 실제 운영 환경 검증이 아니다
값 4: cleanup=1
이 파일에서 계속 확인할 고정 단서가 cleanup=1다.
- 코드 연결
F17 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- Docker·port·자격증명이 필요하다
값 5: container_absent
이 파일에서 계속 확인할 고정 단서가 container_absent다.
- 코드 연결
F17 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- 강제 실패 경로도 cleanup 책임을 유지한다
STEP 04 / 13
비유 ↔ 코드 전체 연결표
감사 규칙상 연결 대상인 원본 25줄을 빠짐없이 연결합니다.
| 줄 | 정확한 원본 줄 | STARRY 비유 | 실제 뜻·입력·결과·한계 |
|---|---|---|---|
| 1줄F17-L01 | param( |
출고표 1번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 PowerShell script가 받을 입력 계약을 연다.
|
| 2줄F17-L02 | $ErrorActionPreference= |
출고표 2번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 PowerShell 오류를 계속 진행하지 않고 중단시키는 기본 정책을 둔다.
|
| 3줄F17-L03 | if( |
출고표 3번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 learner project의 Gradle wrapper로 지정 task를 실행한다.
|
| 4줄F17-L04 | New-Item -ItemType Directory -Force $e|Out-Null; |
출고표 4번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 container·volume·process가 남지 않았는지 lifecycle evidence에 기록한다.
|
| 5줄F17-L05 | $env: |
출고표 5번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 6줄F17-L06 | Push-Location $learner |
출고표 6번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 run-w24-lifecycle.ps1의 다음 검증 또는 설명 단계를 구성한다.
|
| 7줄F17-L07 | try{ |
출고표 7번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 조건·반복·함수의 실행 block을 연다.
|
| 8줄F17-L08 | & docker compose -f $compose -p $ComposeProject up -d --wait db; |
출고표 8번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 native process 종료 코드를 검사해 실패를 놓치지 않는다.
|
| 9줄F17-L09 | $container= |
출고표 9번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 native process 종료 코드를 검사해 실패를 놓치지 않는다.
|
| 10줄F17-L10 | $stdout= |
출고표 10번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 learner project의 Gradle wrapper로 지정 task를 실행한다.
|
| 11줄F17-L11 | $health= |
출고표 11번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 HTTP API를 호출해 status와 JSON response를 받는다.
|
| 12줄F17-L12 | $listen= |
출고표 12번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 13줄F17-L13 | & powershell. |
출고표 13번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 native process 종료 코드를 검사해 실패를 놓치지 않는다.
|
| 14줄F17-L14 | $body= |
출고표 14번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 15줄F17-L15 | }catch{ |
출고표 15번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 중간 실패가 있어도 반드시 실행할 cleanup 경계를 연다.
|
| 16줄F17-L16 | if( |
출고표 16번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 성공·실패 뒤 남은 host JVM을 정리한다.
|
| 17줄F17-L17 | & docker compose -f $compose -p $ComposeProject down -v|Out-Null; |
출고표 17번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 native process 종료 코드를 검사해 실패를 놓치지 않는다.
|
| 18줄F17-L18 | $containers= |
출고표 18번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 native process 종료 코드를 검사해 실패를 놓치지 않는다.
|
| 19줄F17-L19 | $volumeName= |
출고표 19번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 native process 종료 코드를 검사해 실패를 놓치지 않는다.
|
| 20줄F17-L20 | Pop-Location; |
출고표 20번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 runtime에만 둔 DB·demo secret 환경변수를 정리한다.
|
| 21줄F17-L21 | } |
출고표 21번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 22줄F17-L22 | if( |
출고표 22번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 container·volume·process가 남지 않았는지 lifecycle evidence에 기록한다.
|
| 23줄F17-L23 | if( |
출고표 23번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 24줄F17-L24 | $body. |
출고표 24번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 검증된 object를 JSON evidence text로 직렬화한다.
|
| 25줄F17-L25 | "W24_LIFECYCLE_GREEN project= |
출고표 25번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 container·volume·process가 남지 않았는지 lifecycle evidence에 기록한다.
|
STEP 05 / 13
원본 코드 조각
원본을 3개 의미 조각으로 나누어 그대로 확인합니다.
파일을 한꺼번에 외우지 않고 실행 의미가 이어지는 작은 조각으로 봅니다. 아래 코드는 hash로 고정한 native 정본 source에서 그대로 잘랐습니다.
param([Parameter(Mandatory=$true)][string]$ProjectRoot,[Parameter(Mandatory=$true)][string]$EvidenceDir,[string]$ComposeProject='w24-learner-demo',[int]$Port=28080,[int]$DbPort=62440,[switch]$ForceFailureAfterCompose)
$ErrorActionPreference='Stop';$referenceRoot=Split-Path -Parent $PSScriptRoot;$learner=(Resolve-Path -LiteralPath $ProjectRoot).Path;$e=[IO.Path]::GetFullPath($EvidenceDir)
if(!(Test-Path -LiteralPath (Join-Path $learner 'gradlew.bat') -PathType Leaf)){throw 'W24 learner gradlew.bat missing'}
New-Item -ItemType Directory -Force $e|Out-Null;$proc=$null;$appPid=$null;$cleanupResponsible=$true;$body=$null;$caught=$null;$compose=Join-Path $referenceRoot 'compose.yaml';if(!(Test-Path -LiteralPath $compose)){throw 'W24 packaged DB-only compose.yaml missing'}
$env:FCL_DB_PASSWORD='w24-disposable-password';$env:FCL_DB_PORT="$DbPort";$env:SPRING_DATASOURCE_URL="jdbc:postgresql://localhost:$DbPort/financial_core";$env:SPRING_DATASOURCE_USERNAME='app';$env:SPRING_DATASOURCE_PASSWORD=$env:FCL_DB_PASSWORD;$env:SERVER_PORT="$Port";$env:FCL_DEMO_USER='customer-1';$env:FCL_DEMO_PASSWORD='password'
Push-Location $learner
try{
& docker compose -f $compose -p $ComposeProject up -d --wait db;if($LASTEXITCODE-ne 0){throw "W24 compose up exit=$LASTEXITCODE"};if($ForceFailureAfterCompose){throw 'W24 forced partial-startup failure'}
$container=(& docker compose -f $compose -p $ComposeProject ps -q db).Trim();if($LASTEXITCODE-ne 0-or[string]::IsNullOrWhiteSpace($container)){throw 'W24 DB container resolution failed'}
$stdout=Join-Path $e 'host.stdout.log';$stderr=Join-Path $e 'host.stderr.log';$proc=Start-Process -FilePath (Join-Path $learner 'gradlew.bat') -ArgumentList @('bootRun','--no-daemon') -WorkingDirectory $learner -PassThru -WindowStyle Hidden -RedirectStandardOutput $stdout -RedirectStandardError $stderr
$health=$null;for($i=0;$i-lt 90;$i++){if($proc.HasExited){throw "W24 host app exited=$($proc.ExitCode)"};try{$health=Invoke-RestMethod "http://localhost:$Port/actuator/health" -TimeoutSec 2;if($health.status-eq'UP'){break}}catch{};Start-Sleep 1};if(!$health-or$health.status-ne'UP'){throw 'W24 readiness never UP'}
$listen=Get-NetTCPConnection -State Listen -LocalPort $Port -ErrorAction SilentlyContinue;if(!$listen){throw 'W24 listener missing'};$appPid=[int]$listen[0].OwningProcess
& powershell.exe -NoProfile -ExecutionPolicy Bypass -File (Join-Path $referenceRoot 'scripts/run-w24-demo.ps1') -EvidencePath (Join-Path $e 'demo-run.txt') -BaseUrl "http://localhost:$Port" -Container $container;if($LASTEXITCODE-ne 0){throw "W24 demo exit=$LASTEXITCODE"}
$body=[ordered]@{compose_project=$ComposeProject;runtime='host JVM';port=$Port;health='UP';demo='GREEN';native_exit=0}
}catch{$caught=$_}finally{
if($appPid){Stop-Process -Id $appPid -Force -ErrorAction SilentlyContinue};if($proc-and!$proc.HasExited){Stop-Process -Id $proc.Id -Force -ErrorAction SilentlyContinue}
& docker compose -f $compose -p $ComposeProject down -v|Out-Null;$downExit=$LASTEXITCODE
$containers=@(& docker compose -f $compose -p $ComposeProject ps -q);$containerAbsent=($LASTEXITCODE-eq 0-and$containers.Count-eq 0)
$volumeName="${ComposeProject}_financial-core-db";$volumes=@(& docker volume ls -q --filter "name=^${volumeName}$");$volumeAbsent=($LASTEXITCODE-eq 0-and$volumes.Count-eq 0)
Pop-Location;Remove-Item Env:FCL_DB_PASSWORD,Env:FCL_DB_PORT,Env:SPRING_DATASOURCE_URL,Env:SPRING_DATASOURCE_USERNAME,Env:SPRING_DATASOURCE_PASSWORD,Env:SERVER_PORT,Env:FCL_DEMO_USER,Env:FCL_DEMO_PASSWORD -ErrorAction SilentlyContinue
}
if($downExit-ne 0-or-not$containerAbsent-or-not$volumeAbsent){throw "W24 cleanup verification failed down=$downExit container_absent=$containerAbsent volume_absent=$volumeAbsent"}
if($caught){throw $caught}
$body.cleanup=1;$body.down_native_exit=$downExit;$body.container_absent=$containerAbsent;$body.volume_absent=$volumeAbsent;$tmp=Join-Path $e 'lifecycle.json.tmp';$final=Join-Path $e 'lifecycle.json';$body|ConvertTo-Json|Set-Content -Encoding utf8 $tmp;Move-Item -LiteralPath $tmp -Destination $final -Force
"W24_LIFECYCLE_GREEN project=$ComposeProject port=$Port health=UP demo=GREEN cleanup=1 native_exit=0"
STEP 06 / 13
코드 한 줄씩 한국어로 번역
비어 있지 않은 25줄을 모두 한국어로 옮깁니다.
비어 있지 않은 원본 줄은 하나도 생략하지 않습니다.
| 줄 | 원본 | 한국어 번역 |
|---|---|---|
| 1 | param([Parameter(Mandatory=$true)][string]$ProjectRoot,[Parameter(Mandatory=$true)][string]$EvidenceDir,[string]$ComposeProject='w24-learner-demo',[int]$Port=28080,[int]$DbPort=62440,[switch]$ForceFailureAfterCompose) | 실행 의미: PowerShell script가 받을 입력 계약을 연다. |
| 2 | $ErrorActionPreference='Stop';$referenceRoot=Split-Path -Parent $PSScriptRoot;$learner=(Resolve-Path -LiteralPath $ProjectRoot).Path;$e=[IO.Path]::GetFullPath($EvidenceDir) | 실행 의미: PowerShell 오류를 계속 진행하지 않고 중단시키는 기본 정책을 둔다. |
| 3 | if(!(Test-Path -LiteralPath (Join-Path $learner 'gradlew.bat') -PathType Leaf)){throw 'W24 learner gradlew.bat missing'} | 실행 의미: learner project의 Gradle wrapper로 지정 task를 실행한다. |
| 4 | New-Item -ItemType Directory -Force $e|Out-Null;$proc=$null;$appPid=$null;$cleanupResponsible=$true;$body=$null;$caught=$null;$compose=Join-Path $referenceRoot 'compose.yaml';if(!(Test-Path -LiteralPath $compose)){throw 'W24 packaged DB-only compose.yaml missing'} | 실행 의미: container·volume·process가 남지 않았는지 lifecycle evidence에 기록한다. |
| 5 | $env:FCL_DB_PASSWORD='w24-disposable-password';$env:FCL_DB_PORT="$DbPort";$env:SPRING_DATASOURCE_URL="jdbc:postgresql://localhost:$DbPort/financial_core";$env:SPRING_DATASOURCE_USERNAME='app';$env:SPRING_DATASOURCE_PASSWORD=$env:FCL_DB_PASSWORD;$env:SERVER_PORT="$Port";$env:FCL_DEMO_USER='customer-1';$env:FCL_DEMO_PASSWORD='password' | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 6 | Push-Location $learner | 실행 의미: run-w24-lifecycle.ps1의 다음 검증 또는 설명 단계를 구성한다. |
| 7 | try{ | 실행 의미: 조건·반복·함수의 실행 block을 연다. |
| 8 | & docker compose -f $compose -p $ComposeProject up -d --wait db;if($LASTEXITCODE-ne 0){throw "W24 compose up exit=$LASTEXITCODE"};if($ForceFailureAfterCompose){throw 'W24 forced partial-startup failure'} | 실행 의미: native process 종료 코드를 검사해 실패를 놓치지 않는다. |
| 9 | $container=(& docker compose -f $compose -p $ComposeProject ps -q db).Trim();if($LASTEXITCODE-ne 0-or[string]::IsNullOrWhiteSpace($container)){throw 'W24 DB container resolution failed'} | 실행 의미: native process 종료 코드를 검사해 실패를 놓치지 않는다. |
| 10 | $stdout=Join-Path $e 'host.stdout.log';$stderr=Join-Path $e 'host.stderr.log';$proc=Start-Process -FilePath (Join-Path $learner 'gradlew.bat') -ArgumentList @('bootRun','--no-daemon') -WorkingDirectory $learner -PassThru -WindowStyle Hidden -RedirectStandardOutput $stdout -RedirectStandardError $stderr | 실행 의미: learner project의 Gradle wrapper로 지정 task를 실행한다. |
| 11 | $health=$null;for($i=0;$i-lt 90;$i++){if($proc.HasExited){throw "W24 host app exited=$($proc.ExitCode)"};try{$health=Invoke-RestMethod "http://localhost:$Port/actuator/health" -TimeoutSec 2;if($health.status-eq'UP'){break}}catch{};Start-Sleep 1};if(!$health-or$health.status-ne'UP'){throw 'W24 readiness never UP'} | 실행 의미: HTTP API를 호출해 status와 JSON response를 받는다. |
| 12 | $listen=Get-NetTCPConnection -State Listen -LocalPort $Port -ErrorAction SilentlyContinue;if(!$listen){throw 'W24 listener missing'};$appPid=[int]$listen[0].OwningProcess | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 13 | & powershell.exe -NoProfile -ExecutionPolicy Bypass -File (Join-Path $referenceRoot 'scripts/run-w24-demo.ps1') -EvidencePath (Join-Path $e 'demo-run.txt') -BaseUrl "http://localhost:$Port" -Container $container;if($LASTEXITCODE-ne 0){throw "W24 demo exit=$LASTEXITCODE"} | 실행 의미: native process 종료 코드를 검사해 실패를 놓치지 않는다. |
| 14 | $body=[ordered]@{compose_project=$ComposeProject;runtime='host JVM';port=$Port;health='UP';demo='GREEN';native_exit=0} | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 15 | }catch{$caught=$_}finally{ | 실행 의미: 중간 실패가 있어도 반드시 실행할 cleanup 경계를 연다. |
| 16 | if($appPid){Stop-Process -Id $appPid -Force -ErrorAction SilentlyContinue};if($proc-and!$proc.HasExited){Stop-Process -Id $proc.Id -Force -ErrorAction SilentlyContinue} | 실행 의미: 성공·실패 뒤 남은 host JVM을 정리한다. |
| 17 | & docker compose -f $compose -p $ComposeProject down -v|Out-Null;$downExit=$LASTEXITCODE | 실행 의미: native process 종료 코드를 검사해 실패를 놓치지 않는다. |
| 18 | $containers=@(& docker compose -f $compose -p $ComposeProject ps -q);$containerAbsent=($LASTEXITCODE-eq 0-and$containers.Count-eq 0) | 실행 의미: native process 종료 코드를 검사해 실패를 놓치지 않는다. |
| 19 | $volumeName="${ComposeProject}_financial-core-db";$volumes=@(& docker volume ls -q --filter "name=^${volumeName}$");$volumeAbsent=($LASTEXITCODE-eq 0-and$volumes.Count-eq 0) | 실행 의미: native process 종료 코드를 검사해 실패를 놓치지 않는다. |
| 20 | Pop-Location;Remove-Item Env:FCL_DB_PASSWORD,Env:FCL_DB_PORT,Env:SPRING_DATASOURCE_URL,Env:SPRING_DATASOURCE_USERNAME,Env:SPRING_DATASOURCE_PASSWORD,Env:SERVER_PORT,Env:FCL_DEMO_USER,Env:FCL_DEMO_PASSWORD -ErrorAction SilentlyContinue | 실행 의미: runtime에만 둔 DB·demo secret 환경변수를 정리한다. |
| 21 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 22 | if($downExit-ne 0-or-not$containerAbsent-or-not$volumeAbsent){throw "W24 cleanup verification failed down=$downExit container_absent=$containerAbsent volume_absent=$volumeAbsent"} | 실행 의미: container·volume·process가 남지 않았는지 lifecycle evidence에 기록한다. |
| 23 | if($caught){throw $caught} | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 24 | $body.cleanup=1;$body.down_native_exit=$downExit;$body.container_absent=$containerAbsent;$body.volume_absent=$volumeAbsent;$tmp=Join-Path $e 'lifecycle.json.tmp';$final=Join-Path $e 'lifecycle.json';$body|ConvertTo-Json|Set-Content -Encoding utf8 $tmp;Move-Item -LiteralPath $tmp -Destination $final -Force | 실행 의미: 검증된 object를 JSON evidence text로 직렬화한다. |
| 25 | "W24_LIFECYCLE_GREEN project=$ComposeProject port=$Port health=UP demo=GREEN cleanup=1 native_exit=0" | 실행 의미: container·volume·process가 남지 않았는지 lifecycle evidence에 기록한다. |
STEP 07 / 13
기존 수준의 한 줄 읽기·문법 해부
쉬운 설명 다음에 문법과 실행 순서를 정밀하게 읽습니다.
한 줄로 읽기run-w24-lifecycle.ps1 — DB·host JVM·demo·cleanup 책임는 disposable DB Compose와 host JVM을 띄워 readiness와 demo를 확인하고 성공·실패 모두에서 process·container·volume·secret 환경변수를 정리한다.
문법 해부
- .ps1 문법에서 선언·조건·pipeline·block 경계를 먼저 나눈다.
- expected 값과 actual 결과를 같은 이름처럼 보여도 서로 다른 source로 읽는다.
- native exit·row count·hash·사람 판정을 서로 대체하지 않는다.
실행 순서
- 입력 경로·fixture·환경변수·expected 계약을 고정한다.
- source가 실행하는 native process·HTTP·SQL 또는 형식 검사를 따라간다.
- actual 값과 exact marker를 대조하고 실패면 성공 발행 전에 중단한다.
- finally cleanup과 비범위를 evidence에 남긴다.
W24 조각별 정밀 해설
F17-C01 · 원문 1–12줄
- 문법 해부
- .ps1 문법으로 1–12줄의 선언·조건·pipeline·block을 나눈다.
- 실제 값 추적
- port=28080, dbPort=62440, health=UP를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- expected와 actual이 일치하고 owner evidence가 같은 run/hash에 연결되는 경우다.
- 틀린 예·반례
- Docker·port·자격증명이 필요하다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- 파일 존재·문자열·hash·exit0 하나를 의미 Green 전체와 같다고 보지 않는다.
- 하지 않는 일
- Docker·port·자격증명이 필요하다; 강제 실패 경로도 cleanup 책임을 유지한다; 실제 운영 환경 검증이 아니다
- 다음 연결
- 다음 조각 또는 F17 evidence 판정으로 상태를 넘긴다.
F17-C02 · 원문 13–24줄
- 문법 해부
- .ps1 문법으로 13–24줄의 선언·조건·pipeline·block을 나눈다.
- 실제 값 추적
- port=28080, dbPort=62440, health=UP를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- expected와 actual이 일치하고 owner evidence가 같은 run/hash에 연결되는 경우다.
- 틀린 예·반례
- Docker·port·자격증명이 필요하다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- 파일 존재·문자열·hash·exit0 하나를 의미 Green 전체와 같다고 보지 않는다.
- 하지 않는 일
- Docker·port·자격증명이 필요하다; 강제 실패 경로도 cleanup 책임을 유지한다; 실제 운영 환경 검증이 아니다
- 다음 연결
- 다음 조각 또는 F17 evidence 판정으로 상태를 넘긴다.
F17-C03 · 원문 25–25줄
- 문법 해부
- .ps1 문법으로 25–25줄의 선언·조건·pipeline·block을 나눈다.
- 실제 값 추적
- port=28080, dbPort=62440, health=UP를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- expected와 actual이 일치하고 owner evidence가 같은 run/hash에 연결되는 경우다.
- 틀린 예·반례
- Docker·port·자격증명이 필요하다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- 파일 존재·문자열·hash·exit0 하나를 의미 Green 전체와 같다고 보지 않는다.
- 하지 않는 일
- Docker·port·자격증명이 필요하다; 강제 실패 경로도 cleanup 책임을 유지한다; 실제 운영 환경 검증이 아니다
- 다음 연결
- 다음 조각 또는 F17 evidence 판정으로 상태를 넘긴다.
실행 순서 — run-w24-lifecycle.ps1 — DB·host JVM·demo·cleanup 책임
-
dbPort=62440가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 disposable DB Compose와 host JVM을 띄워 readiness와 demo를 확인하고 성공·실패 모두에서 process·container·volume·secret 환경변수를 정리한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘강제 실패 경로도 cleanup 책임을 유지한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 dbPort=62440와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 08 / 13
실제 값 따라가기
같은 입력값이 어느 줄을 지나 어떤 결과가 되는지 추적합니다.
| 순서 | 들어온 값 | 코드가 하는 일 | 나온 값·상태 | 경계 |
|---|---|---|---|---|
| 입력 | port=28080 | source 계약에 대입 | F17 실행/설명 시작 상태 | Docker·port·자격증명이 필요하다 |
| 검증 | dbPort=62440 | expected와 actual 또는 형식 대조 | 통과 또는 첫 mismatch | 강제 실패 경로도 cleanup 책임을 유지한다 |
| 증거 | volume_absent | marker·hash·row를 같은 run에 연결 | 범위가 적힌 evidence 후보 | 실제 운영 환경 검증이 아니다 |
실제 값 — run-w24-lifecycle.ps1 — DB·host JVM·demo·cleanup 책임
-
health=UP가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 disposable DB Compose와 host JVM을 띄워 readiness와 demo를 확인하고 성공·실패 모두에서 process·container·volume·secret 환경변수를 정리한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘실제 운영 환경 검증이 아니다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 health=UP와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 09 / 13
Gradle·PowerShell·HTTP·PostgreSQL 내부에서 벌어지는 일
Gradle·JUnit XML·PowerShell·HTTP·PostgreSQL·Docker에서 실제로 일어나는 일과 증명 범위를 구분합니다.
run-w24-lifecycle.ps1 bytes와 expected 값을 읽는다.
파일 존재만으로 runtime 성공은 아니다.native exit·HTTP status·JUnit XML·DB row·hash 중 이 파일이 소유한 값을 만든다.
Docker·port·자격증명이 필요하다관련 evidence와 사람 의미 검토를 release 후보에 연결한다.
실제 운영 환경 검증이 아니다첫 실패 경계 — run-w24-lifecycle.ps1 — DB·host JVM·demo·cleanup 책임
-
cleanup=1가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 disposable DB Compose와 host JVM을 띄워 readiness와 demo를 확인하고 성공·실패 모두에서 process·container·volume·secret 환경변수를 정리한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘Docker·port·자격증명이 필요하다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 cleanup=1와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 10 / 13
흔한 착각과 틀린 예
그럴듯하지만 틀린 해석을 반례로 고칩니다.
❌ port=28080 문자열이 source에 있으니 실제 실행도 Green이다.
왜 틀리나 source literal과 runtime 관찰값은 다른 증거다.
바르게 읽기 native exit·actual XML/HTTP/DB evidence를 별도로 확인한다.
반례 script가 실행 전 경로 오류로 멈춰도 literal은 그대로 남는다.
❌ 파일 SHA-256이 있으면 내용의 의미와 사실성도 검증됐다.
왜 틀리나 hash는 동일 bytes만 말한다.
바르게 읽기 schema·수치·질문·근거는 별도 자동 또는 사람 판정을 거친다.
반례 빈 review 질문을 가진 CSV도 안정된 hash를 가진다.
❌ LOCAL_ARTIFACT_VALIDATED는 release Green과 같다.
왜 틀리나 generic validator는 파일 shape만 확인한다.
바르게 읽기 HUMAN_SEMANTIC_REVIEW_REQUIRED를 유지한다.
반례 잘못된 track 점수표도 byte 수 조건은 통과할 수 있다.
❌ 이 파일이 W24 전체 lifecycle을 모두 소유한다.
왜 틀리나 각 source는 Gate·demo·cleanup·사람 review 중 일부만 담당한다.
바르게 읽기 owner와 non-responsibility를 release manifest에서 분리한다.
반례 D4 source audit에는 runtime_claim=false가 명시된다.
❌ 이전 주 Green이나 오래된 log를 현재 commit 결과로 재사용한다.
왜 틀리나 source·commit·actual result가 같은 실행에 묶이지 않는다.
바르게 읽기 release 후보에서 새 evidence와 hash를 만든다.
반례 expected JSON이 바뀌면 예전 XML은 exact inventory를 증명하지 못한다.
STEP 11 / 13
이 코드가 보장하지 않는 것
이 코드가 책임지지 않는 일을 분리합니다.
Docker·port·자격증명이 필요하다
이 책임을 맡는 곳: runtime Gate강제 실패 경로도 cleanup 책임을 유지한다
이 책임을 맡는 곳: external/human review실제 운영 환경 검증이 아니다
이 책임을 맡는 곳: release manifestDocker·port·자격증명이 필요하다
이 책임을 맡는 곳: 운영 환경증명하지 않는 범위 — run-w24-lifecycle.ps1 — DB·host JVM·demo·cleanup 책임
-
container_absent가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 disposable DB Compose와 host JVM을 띄워 readiness와 demo를 확인하고 성공·실패 모두에서 process·container·volume·secret 환경변수를 정리한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘강제 실패 경로도 cleanup 책임을 유지한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 container_absent와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 12 / 13
직접 다시 써보기
뜻 → 조각 → 전체 코드 순서로 다시 씁니다.
1단계 · 뜻부터 복원
- disposable DB Compose와 host JVM을 띄워 readiness와 demo를 확인하고 성공·실패 모두에서 process·container·volume·secret 환경변수를 정리한다.
- 핵심 값은 port=28080, dbPort=62440, health=UP, cleanup=1, container_absent, volume_absent다.
2단계 · 코드 조각 재조립
- 1. PowerShell script가 받을 입력 계약을 연다
- 2. PowerShell 오류를 계속 진행하지 않고 중단시키는 기본 정책을 둔다
- 3. learner project의 Gradle wrapper로 지정 task를 실행한다
- 4. container·volume·process가 남지 않았는지 lifecycle evidence에 기록한다
- 5. 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다
- 6. run-w24-lifecycle.ps1의 다음 검증 또는 설명 단계를 구성한다
- 7. 조건·반복·함수의 실행 block을 연다
- 8. native process 종료 코드를 검사해 실패를 놓치지 않는다
3단계 · 파일 전체 다시 쓰기
scripts/run-w24-lifecycle.ps1을 새 파일에 다시 쓰고 expected·actual·실패·cleanup·비범위를 주석으로 표시한다.
자가 점검
- 비어 있지 않은 모든 source 줄을 한 번씩 읽었나?
- source shape와 runtime Green을 분리했나?
- 사람 검토·외부 상태를 자동 성공으로 꾸미지 않았나?
- 첫 실패와 cleanup 책임을 설명할 수 있나?
STEP 13 / 13
전체 원본 source
감사로 고정한 전체 source를 가감 없이 확인합니다.
원문 정본 전체 source 확인하기
param([Parameter(Mandatory=$true)][string]$ProjectRoot,[Parameter(Mandatory=$true)][string]$EvidenceDir,[string]$ComposeProject='w24-learner-demo',[int]$Port=28080,[int]$DbPort=62440,[switch]$ForceFailureAfterCompose)
$ErrorActionPreference='Stop';$referenceRoot=Split-Path -Parent $PSScriptRoot;$learner=(Resolve-Path -LiteralPath $ProjectRoot).Path;$e=[IO.Path]::GetFullPath($EvidenceDir)
if(!(Test-Path -LiteralPath (Join-Path $learner 'gradlew.bat') -PathType Leaf)){throw 'W24 learner gradlew.bat missing'}
New-Item -ItemType Directory -Force $e|Out-Null;$proc=$null;$appPid=$null;$cleanupResponsible=$true;$body=$null;$caught=$null;$compose=Join-Path $referenceRoot 'compose.yaml';if(!(Test-Path -LiteralPath $compose)){throw 'W24 packaged DB-only compose.yaml missing'}
$env:FCL_DB_PASSWORD='w24-disposable-password';$env:FCL_DB_PORT="$DbPort";$env:SPRING_DATASOURCE_URL="jdbc:postgresql://localhost:$DbPort/financial_core";$env:SPRING_DATASOURCE_USERNAME='app';$env:SPRING_DATASOURCE_PASSWORD=$env:FCL_DB_PASSWORD;$env:SERVER_PORT="$Port";$env:FCL_DEMO_USER='customer-1';$env:FCL_DEMO_PASSWORD='password'
Push-Location $learner
try{
& docker compose -f $compose -p $ComposeProject up -d --wait db;if($LASTEXITCODE-ne 0){throw "W24 compose up exit=$LASTEXITCODE"};if($ForceFailureAfterCompose){throw 'W24 forced partial-startup failure'}
$container=(& docker compose -f $compose -p $ComposeProject ps -q db).Trim();if($LASTEXITCODE-ne 0-or[string]::IsNullOrWhiteSpace($container)){throw 'W24 DB container resolution failed'}
$stdout=Join-Path $e 'host.stdout.log';$stderr=Join-Path $e 'host.stderr.log';$proc=Start-Process -FilePath (Join-Path $learner 'gradlew.bat') -ArgumentList @('bootRun','--no-daemon') -WorkingDirectory $learner -PassThru -WindowStyle Hidden -RedirectStandardOutput $stdout -RedirectStandardError $stderr
$health=$null;for($i=0;$i-lt 90;$i++){if($proc.HasExited){throw "W24 host app exited=$($proc.ExitCode)"};try{$health=Invoke-RestMethod "http://localhost:$Port/actuator/health" -TimeoutSec 2;if($health.status-eq'UP'){break}}catch{};Start-Sleep 1};if(!$health-or$health.status-ne'UP'){throw 'W24 readiness never UP'}
$listen=Get-NetTCPConnection -State Listen -LocalPort $Port -ErrorAction SilentlyContinue;if(!$listen){throw 'W24 listener missing'};$appPid=[int]$listen[0].OwningProcess
& powershell.exe -NoProfile -ExecutionPolicy Bypass -File (Join-Path $referenceRoot 'scripts/run-w24-demo.ps1') -EvidencePath (Join-Path $e 'demo-run.txt') -BaseUrl "http://localhost:$Port" -Container $container;if($LASTEXITCODE-ne 0){throw "W24 demo exit=$LASTEXITCODE"}
$body=[ordered]@{compose_project=$ComposeProject;runtime='host JVM';port=$Port;health='UP';demo='GREEN';native_exit=0}
}catch{$caught=$_}finally{
if($appPid){Stop-Process -Id $appPid -Force -ErrorAction SilentlyContinue};if($proc-and!$proc.HasExited){Stop-Process -Id $proc.Id -Force -ErrorAction SilentlyContinue}
& docker compose -f $compose -p $ComposeProject down -v|Out-Null;$downExit=$LASTEXITCODE
$containers=@(& docker compose -f $compose -p $ComposeProject ps -q);$containerAbsent=($LASTEXITCODE-eq 0-and$containers.Count-eq 0)
$volumeName="${ComposeProject}_financial-core-db";$volumes=@(& docker volume ls -q --filter "name=^${volumeName}$");$volumeAbsent=($LASTEXITCODE-eq 0-and$volumes.Count-eq 0)
Pop-Location;Remove-Item Env:FCL_DB_PASSWORD,Env:FCL_DB_PORT,Env:SPRING_DATASOURCE_URL,Env:SPRING_DATASOURCE_USERNAME,Env:SPRING_DATASOURCE_PASSWORD,Env:SERVER_PORT,Env:FCL_DEMO_USER,Env:FCL_DEMO_PASSWORD -ErrorAction SilentlyContinue
}
if($downExit-ne 0-or-not$containerAbsent-or-not$volumeAbsent){throw "W24 cleanup verification failed down=$downExit container_absent=$containerAbsent volume_absent=$volumeAbsent"}
if($caught){throw $caught}
$body.cleanup=1;$body.down_native_exit=$downExit;$body.container_absent=$containerAbsent;$body.volume_absent=$volumeAbsent;$tmp=Join-Path $e 'lifecycle.json.tmp';$final=Join-Path $e 'lifecycle.json';$body|ConvertTo-Json|Set-Content -Encoding utf8 $tmp;Move-Item -LiteralPath $tmp -Destination $final -Force
"W24_LIFECYCLE_GREEN project=$ComposeProject port=$Port health=UP demo=GREEN cleanup=1 native_exit=0"