W25 · 단일 트랙 불변식
25주차 코드 뒤풀이: 한 트랙으로 Red부터 누적 Green까지
기본 트랙은 SECURITIES(증권)이며 CARD는 비교용으로 함께 보여 줍니다. Prepare부터 Review까지 순서대로 따라가되 실제 test 단계는 RecordRed·RecordGreen·Cumulative뿐이며, packaged 1_000→700/300과 manifest 10_000 finalState, XML hash와 보존 bytes를 구분합니다. 이 HTML은 코드를 실행하지 않았으므로 실행 상태는 NOT_RUN입니다.
01apply-track-learning-stage.ps1 — 7단계의 단일 진입점
scripts/apply-track-learning-stage.ps1
패키지 정본 보조 계약 · exact PowerShell bytes · 정본 · W25-F0128줄 연결28줄 번역3 chunks
apply-track-learning-stage.ps1 — 7단계의 단일 진입점
scripts/apply-track-learning-stage.ps1
패키지 정본 보조 계약 · exact PowerShell bytes · 정본 · W25-F01STEP 01 / 13
오늘 이 코드에서 해결할 문제
무엇을 이해해야 하는지 질문부터 잡습니다.
서로 다른 reference/learner root와 W25 phase를 fail-closed Python runtime에 전달한다.
- Week=25은 어느 source와 실제 결과에서 확인해야 할까?
- 첫 실패를 만드는 조건과 fail-closed 지점은 어디일까?
- 왜 ‘reference와 learner root는 서로 달라야 한다’를 별도 경계로 남겨야 할까?
Week=25Prepare→ReviewTimeoutSeconds=1200distinct rootsnative exit왜 필요한가 — apply-track-learning-stage.ps1 — 7단계의 단일 진입점
-
Week=25가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 서로 다른 reference/learner root와 W25 phase를 fail-closed Python runtime에 전달한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘reference와 learner root는 서로 달라야 한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 Week=25와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 02 / 13
아주 짧게: 이 코드는 왜 필요할까?
웹소설 대신 이 코드가 필요한 이유만 두 문단으로 쉽게 봅니다.
사용자의 기본 선택에 따라 이 HTML은 SECURITIES(증권)을 주 트랙으로 읽는다. CARD는 비교용이며 명시적으로 고르면 기본값을 덮어쓸 수 있다. 실제 실행은 최종 선택 한 개를 selected-track.csv·근거·state에 같은 값으로 기록하고 reference와 learner 폴더를 분리한 뒤에만 시작한다. 이 HTML 자체는 Gradle/JUnit을 실행하지 않아 NOT_RUN 상태다.
한 통장만 골라 빨강에서 초록까지 증명하는 일주일
이 파일은 서로 다른 reference/learner root와 W25 phase를 fail-closed Python runtime에 전달한다. 눈으로 읽을 때는 각 줄을 검수표 한 칸처럼 보고, 입력과 다음 상태를 놓치지 않는다.
마지막 도장은 hash 확인, 세 test phase의 실제 JUnit 실행, XML bytes archive, 사람 review를 서로 구분한 뒤에만 찍는다. Review는 새 test가 아니며 Q41은 stage runtime 밖의 별도 NOT_RUN 과제, sealed official status는 USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED다. 특히 reference와 learner root는 서로 달라야 한다
딱 여기까지만 비유와 SECURITIES 기본 배지는 실제 selected-track 근거, Gradle/JUnit 실행, XML bytes 보존, 사람 review, Q41 실행, sealed official 확인을 대신하지 않는다.
STEP 03 / 13
초등학생도 이해하는 설명
생활 비유와 실제 코드의 경계를 함께 확인합니다.
값 1: Week=25
이 파일에서 계속 확인할 고정 단서가 Week=25다.
- 코드 연결
F01 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- reference와 learner root는 서로 달라야 한다
값 2: Prepare→Review
이 파일에서 계속 확인할 고정 단서가 Prepare→Review다.
- 코드 연결
F01 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
값 3: TimeoutSeconds=1200
이 파일에서 계속 확인할 고정 단서가 TimeoutSeconds=1200다.
- 코드 연결
F01 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
값 4: distinct roots
이 파일에서 계속 확인할 고정 단서가 distinct roots다.
- 코드 연결
F01 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- wrapper 자체는 manifest나 JUnit XML을 판정하지 않는다
값 5: native exit
이 파일에서 계속 확인할 고정 단서가 native exit다.
- 코드 연결
F01 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- reference와 learner root는 서로 달라야 한다
STEP 04 / 13
비유 ↔ 코드 전체 연결표
감사 규칙상 연결 대상인 원본 28줄을 빠짐없이 연결합니다.
| 줄 | 정확한 원본 줄 | STARRY 비유 | 실제 뜻·입력·결과·한계 |
|---|---|---|---|
| 1줄F01-L01 | param( |
출고표 1번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 PowerShell script가 받을 입력 계약을 연다.
|
| 2줄F01-L02 | [ |
출고표 2번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 이 인자가 빠지면 실행 시작 전에 binding을 거절한다.
|
| 3줄F01-L03 | [ |
출고표 3번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 이 인자가 빠지면 실행 시작 전에 binding을 거절한다.
|
| 4줄F01-L04 | [ |
출고표 4번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 이 인자가 빠지면 실행 시작 전에 binding을 거절한다.
|
| 5줄F01-L05 | [ |
출고표 5번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 이 인자가 빠지면 실행 시작 전에 binding을 거절한다.
|
| 6줄F01-L06 | [ |
출고표 6번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 starter canonical/raw hash만 검증하고 Gradle은 실행하지 않는 phase다.
|
| 7줄F01-L07 | [ |
출고표 7번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 apply-track-learning-stage.ps1의 다음 검증 또는 설명 단계를 구성한다.
|
| 8줄F01-L08 | [ |
출고표 8번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 apply-track-learning-stage.ps1의 다음 검증 또는 설명 단계를 구성한다.
|
| 9줄F01-L09 | [ |
출고표 9번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 apply-track-learning-stage.ps1의 다음 검증 또는 설명 단계를 구성한다.
|
| 10줄F01-L10 | ) |
출고표 10번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 11줄F01-L11 | $ErrorActionPreference= |
출고표 11번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 PowerShell 오류를 계속 진행하지 않고 중단시키는 기본 정책을 둔다.
|
| 12줄F01-L12 | $reference= |
출고표 12번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 입력 경로를 실제 절대 경로로 확인한다.
|
| 13줄F01-L13 | $learner= |
출고표 13번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 입력 경로를 실제 절대 경로로 확인한다.
|
| 14줄F01-L14 | if( |
출고표 14번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 조건·반복·함수의 실행 block을 연다.
|
| 15줄F01-L15 | throw 'ReferenceRoot and LearnerRoot must be different directories' |
출고표 15번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 16줄F01-L16 | } |
출고표 16번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 17줄F01-L17 | $tool= |
출고표 17번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 18줄F01-L18 | if( |
출고표 18번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 필수 파일이나 경로가 실제로 있는지 확인한다.
|
| 19줄F01-L19 | if( |
출고표 19번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 조건·반복·함수의 실행 block을 연다.
|
| 20줄F01-L20 | $py= |
출고표 20번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 21줄F01-L21 | if( |
출고표 21번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 apply-track-learning-stage.ps1의 다음 검증 또는 설명 단계를 구성한다.
|
| 22줄F01-L22 | else{ |
출고표 22번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 조건·반복·함수의 실행 block을 연다.
|
| 23줄F01-L23 | $pythonCommand= |
출고표 23번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 24줄F01-L24 | $command= |
출고표 24번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 25줄F01-L25 | } |
출고표 25번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 26줄F01-L26 | }else{ |
출고표 26번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 apply-track-learning-stage.ps1의 다음 검증 또는 설명 단계를 구성한다.
|
| 27줄F01-L27 | & $command @prefix -B $tool --reference-root $reference --learner-root $learner --week $Week --phase $Phase --timeout-seconds $TimeoutSeconds |
출고표 27번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 apply-track-learning-stage.ps1의 다음 검증 또는 설명 단계를 구성한다.
|
| 28줄F01-L28 | if( |
출고표 28번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 native process 종료 코드를 검사해 실패를 놓치지 않는다.
|
STEP 05 / 13
원본 코드 조각
원본을 3개 의미 조각으로 나누어 그대로 확인합니다.
파일을 한꺼번에 외우지 않고 실행 의미가 이어지는 작은 조각으로 봅니다. 아래 코드는 hash로 고정한 native 정본 source에서 그대로 잘랐습니다.
param(
[Parameter(Mandatory=$true)][string]$ReferenceRoot,
[Parameter(Mandatory=$true)][string]$LearnerRoot,
[Parameter(Mandatory=$true)][ValidateRange(25,38)][int]$Week,
[Parameter(Mandatory=$true)]
[ValidateSet('Prepare','VerifyStarter','RecordRed','VerifySolution','RecordGreen','Cumulative','Review')]
[string]$Phase,
[ValidateRange(1,7200)][int]$TimeoutSeconds=1200,
[string]$Python=''
)
$ErrorActionPreference='Stop'
$reference=(Resolve-Path -LiteralPath $ReferenceRoot -ErrorAction Stop).Path
$learner=(Resolve-Path -LiteralPath $LearnerRoot -ErrorAction Stop).Path
if([string]::Equals($reference,$learner,[StringComparison]::OrdinalIgnoreCase)){
throw 'ReferenceRoot and LearnerRoot must be different directories'
}
$tool=Join-Path $reference 'scripts/track_progressive_runtime.py'
if(!(Test-Path -LiteralPath $tool -PathType Leaf)){throw "runtime missing: $tool"}
if([string]::IsNullOrWhiteSpace($Python)){
$py=Get-Command py -ErrorAction SilentlyContinue
if($null-ne$py){$command=$py.Source;$prefix=@('-3')}
else{
$pythonCommand=Get-Command python -ErrorAction Stop
$command=$pythonCommand.Source;$prefix=@()
}
}else{$command=$Python;$prefix=@()}
& $command @prefix -B $tool --reference-root $reference --learner-root $learner --week $Week --phase $Phase --timeout-seconds $TimeoutSeconds
if($LASTEXITCODE-ne 0){throw "track stage failed: W${Week} phase=$Phase exit=$LASTEXITCODE"}
STEP 06 / 13
코드 한 줄씩 한국어로 번역
비어 있지 않은 28줄을 모두 한국어로 옮깁니다.
비어 있지 않은 원본 줄은 하나도 생략하지 않습니다.
| 줄 | 원본 | 한국어 번역 |
|---|---|---|
| 1 | param( | 실행 의미: PowerShell script가 받을 입력 계약을 연다. |
| 2 | [Parameter(Mandatory=$true)][string]$ReferenceRoot, | 실행 의미: 이 인자가 빠지면 실행 시작 전에 binding을 거절한다. |
| 3 | [Parameter(Mandatory=$true)][string]$LearnerRoot, | 실행 의미: 이 인자가 빠지면 실행 시작 전에 binding을 거절한다. |
| 4 | [Parameter(Mandatory=$true)][ValidateRange(25,38)][int]$Week, | 실행 의미: 이 인자가 빠지면 실행 시작 전에 binding을 거절한다. |
| 5 | [Parameter(Mandatory=$true)] | 실행 의미: 이 인자가 빠지면 실행 시작 전에 binding을 거절한다. |
| 6 | [ValidateSet('Prepare','VerifyStarter','RecordRed','VerifySolution','RecordGreen','Cumulative','Review')] | 실행 의미: starter canonical/raw hash만 검증하고 Gradle은 실행하지 않는 phase다. |
| 7 | [string]$Phase, | 실행 의미: apply-track-learning-stage.ps1의 다음 검증 또는 설명 단계를 구성한다. |
| 8 | [ValidateRange(1,7200)][int]$TimeoutSeconds=1200, | 실행 의미: apply-track-learning-stage.ps1의 다음 검증 또는 설명 단계를 구성한다. |
| 9 | [string]$Python='' | 실행 의미: apply-track-learning-stage.ps1의 다음 검증 또는 설명 단계를 구성한다. |
| 10 | ) | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 11 | $ErrorActionPreference='Stop' | 실행 의미: PowerShell 오류를 계속 진행하지 않고 중단시키는 기본 정책을 둔다. |
| 12 | $reference=(Resolve-Path -LiteralPath $ReferenceRoot -ErrorAction Stop).Path | 실행 의미: 입력 경로를 실제 절대 경로로 확인한다. |
| 13 | $learner=(Resolve-Path -LiteralPath $LearnerRoot -ErrorAction Stop).Path | 실행 의미: 입력 경로를 실제 절대 경로로 확인한다. |
| 14 | if([string]::Equals($reference,$learner,[StringComparison]::OrdinalIgnoreCase)){ | 실행 의미: 조건·반복·함수의 실행 block을 연다. |
| 15 | throw 'ReferenceRoot and LearnerRoot must be different directories' | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 16 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 17 | $tool=Join-Path $reference 'scripts/track_progressive_runtime.py' | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 18 | if(!(Test-Path -LiteralPath $tool -PathType Leaf)){throw "runtime missing: $tool"} | 실행 의미: 필수 파일이나 경로가 실제로 있는지 확인한다. |
| 19 | if([string]::IsNullOrWhiteSpace($Python)){ | 실행 의미: 조건·반복·함수의 실행 block을 연다. |
| 20 | $py=Get-Command py -ErrorAction SilentlyContinue | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 21 | if($null-ne$py){$command=$py.Source;$prefix=@('-3')} | 실행 의미: apply-track-learning-stage.ps1의 다음 검증 또는 설명 단계를 구성한다. |
| 22 | else{ | 실행 의미: 조건·반복·함수의 실행 block을 연다. |
| 23 | $pythonCommand=Get-Command python -ErrorAction Stop | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 24 | $command=$pythonCommand.Source;$prefix=@() | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 25 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 26 | }else{$command=$Python;$prefix=@()} | 실행 의미: apply-track-learning-stage.ps1의 다음 검증 또는 설명 단계를 구성한다. |
| 27 | & $command @prefix -B $tool --reference-root $reference --learner-root $learner --week $Week --phase $Phase --timeout-seconds $TimeoutSeconds | 실행 의미: apply-track-learning-stage.ps1의 다음 검증 또는 설명 단계를 구성한다. |
| 28 | if($LASTEXITCODE-ne 0){throw "track stage failed: W${Week} phase=$Phase exit=$LASTEXITCODE"} | 실행 의미: native process 종료 코드를 검사해 실패를 놓치지 않는다. |
STEP 07 / 13
기존 수준의 한 줄 읽기·문법 해부
쉬운 설명 다음에 문법과 실행 순서를 정밀하게 읽습니다.
한 줄로 읽기apply-track-learning-stage.ps1 — 7단계의 단일 진입점는 서로 다른 reference/learner root와 W25 phase를 fail-closed Python runtime에 전달한다.
문법 해부
- .ps1 문법에서 선언·조건·pipeline·block 경계를 먼저 나눈다.
- manifest의 finalState와 packaged progressive test의 1_000→700/300 oracle을 서로 다른 계약으로 읽는다.
- phase state·native exit·JUnit XML hash·보존된 XML bytes·사람 판정·USER_ATTESTED external status를 서로 대체하지 않는다.
실행 순서
- 기본 트랙은 SECURITIES(증권)이며, 명시적 CARD 선택은 기본값을 덮어쓴다. 실제 실행 전 최종 선택 한 개를 selected-track.csv·근거·state에 같은 값으로 기록하고 서로 다른 reference/learner root를 확인한다.
- Prepare→VerifyStarter→RecordRed→VerifySolution→RecordGreen→Cumulative→Review 순서를 지킨다.
- test를 소유한 세 phase에서만 native exit와 exact JUnit XML 수치를 판정한다.
- 다음 cleanTest 전에 XML bytes를 고유 경로에 보존하고 runtime history hash와 다시 묶는다. Review·Q41·sealed official evidence는 각자의 별도 owner와 검증 수준으로 남긴다.
W25 조각별 정밀 해설
F01-C01 · 원문 1–12줄
- 문법 해부
- .ps1 문법으로 1–12줄의 선언·조건·phase·assert block을 나눈다.
- 실제 값 추적
- Week=25, Prepare→Review, TimeoutSeconds=1200를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- 기본 SECURITIES 또는 명시적으로 덮어쓴 CARD 중 최종 선택 한 개의 selected-track evidence와 runtime 결과에서 expected와 actual이 일치하고 owner evidence가 같은 run/hash 및 보존 XML에 연결되는 경우다. 기본/덮어쓰기 표시만 있고 실행 evidence가 없으면 NOT_RUN이다.
- 틀린 예·반례
- reference와 learner root는 서로 달라야 한다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- phase 이름·manifest finalState·history hash·exit0 하나를 W25 증거 전체와 같다고 보지 않는다.
- 하지 않는 일
- reference와 learner root는 서로 달라야 한다; 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다; 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다; wrapper 자체는 manifest나 JUnit XML을 판정하지 않는다
- 다음 연결
- 다음 조각 또는 F01 evidence 판정으로 상태를 넘긴다.
F01-C02 · 원문 13–24줄
- 문법 해부
- .ps1 문법으로 13–24줄의 선언·조건·phase·assert block을 나눈다.
- 실제 값 추적
- Week=25, Prepare→Review, TimeoutSeconds=1200를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- 기본 SECURITIES 또는 명시적으로 덮어쓴 CARD 중 최종 선택 한 개의 selected-track evidence와 runtime 결과에서 expected와 actual이 일치하고 owner evidence가 같은 run/hash 및 보존 XML에 연결되는 경우다. 기본/덮어쓰기 표시만 있고 실행 evidence가 없으면 NOT_RUN이다.
- 틀린 예·반례
- reference와 learner root는 서로 달라야 한다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- phase 이름·manifest finalState·history hash·exit0 하나를 W25 증거 전체와 같다고 보지 않는다.
- 하지 않는 일
- reference와 learner root는 서로 달라야 한다; 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다; 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다; wrapper 자체는 manifest나 JUnit XML을 판정하지 않는다
- 다음 연결
- 다음 조각 또는 F01 evidence 판정으로 상태를 넘긴다.
F01-C03 · 원문 25–28줄
- 문법 해부
- .ps1 문법으로 25–28줄의 선언·조건·phase·assert block을 나눈다.
- 실제 값 추적
- Week=25, Prepare→Review, TimeoutSeconds=1200를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- 기본 SECURITIES 또는 명시적으로 덮어쓴 CARD 중 최종 선택 한 개의 selected-track evidence와 runtime 결과에서 expected와 actual이 일치하고 owner evidence가 같은 run/hash 및 보존 XML에 연결되는 경우다. 기본/덮어쓰기 표시만 있고 실행 evidence가 없으면 NOT_RUN이다.
- 틀린 예·반례
- reference와 learner root는 서로 달라야 한다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- phase 이름·manifest finalState·history hash·exit0 하나를 W25 증거 전체와 같다고 보지 않는다.
- 하지 않는 일
- reference와 learner root는 서로 달라야 한다; 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다; 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다; wrapper 자체는 manifest나 JUnit XML을 판정하지 않는다
- 다음 연결
- 다음 조각 또는 F01 evidence 판정으로 상태를 넘긴다.
실행 순서 — apply-track-learning-stage.ps1 — 7단계의 단일 진입점
-
Prepare→Review가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 서로 다른 reference/learner root와 W25 phase를 fail-closed Python runtime에 전달한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 Prepare→Review와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 08 / 13
실제 값 따라가기
같은 입력값이 어느 줄을 지나 어떤 결과가 되는지 추적합니다.
| 순서 | 들어온 값 | 코드가 하는 일 | 나온 값·상태 | 경계 |
|---|---|---|---|---|
| 입력 | Week=25 | source 계약에 대입 | F01 실행/설명 시작 상태 | reference와 learner root는 서로 달라야 한다 |
| 검증 | Prepare→Review | expected와 actual 또는 형식 대조 | 통과 또는 첫 mismatch | 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다 |
| 증거 | native exit | marker·hash·row를 같은 run에 연결 | 범위가 적힌 evidence 후보 | wrapper 자체는 manifest나 JUnit XML을 판정하지 않는다 |
실제 값 — apply-track-learning-stage.ps1 — 7단계의 단일 진입점
-
TimeoutSeconds=1200가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 서로 다른 reference/learner root와 W25 phase를 fail-closed Python runtime에 전달한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 TimeoutSeconds=1200와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 09 / 13
Gradle·JUnit XML·PowerShell·SQL 내부에서 벌어지는 일
세 test phase, XML bytes archive, Review, 별도 Q41, USER_ATTESTED sealed 결과의 owner와 증명 범위를 구분합니다.
apply-track-learning-stage.ps1 bytes와 track·phase·hash 계약을 읽는다.
SECURITIES 기본 선택과 파일 존재·phase 이름만으로 runtime Green을 주장할 수 없다. 실제 selected-track evidence와 실행 결과는 별도다.RecordRed·RecordGreen·Cumulative에서만 native exit와 exact JUnit XML을 만든다.
reference와 learner root는 서로 달라야 한다XML bytes를 고유 파일로 보존하고 history hash와 묶은 뒤, Review는 기존 CumulativeGreen만 인용한다. Q41은 별도 PostgreSQL evidence, sealed official status는 user-attested evidence로 남긴다.
wrapper 자체는 manifest나 JUnit XML을 판정하지 않는다첫 실패 경계 — apply-track-learning-stage.ps1 — 7단계의 단일 진입점
-
distinct roots가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 서로 다른 reference/learner root와 W25 phase를 fail-closed Python runtime에 전달한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘wrapper 자체는 manifest나 JUnit XML을 판정하지 않는다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 distinct roots와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 10 / 13
흔한 착각과 틀린 예
그럴듯하지만 틀린 해석을 반례로 고칩니다.
❌ Prepare·VerifyStarter·VerifySolution·Review도 Gradle을 실행해 Green을 만든다.
왜 틀리나 runtime에서 test 실행을 소유하는 phase는 RecordRed·RecordGreen·Cumulative뿐이다.
바르게 읽기 각 phase history의 execution 유무와 mode를 직접 확인한다.
반례 VerifySolution은 solution hash만 검증하므로 새 JUnit XML이 없어야 정상이다.
❌ 기본 트랙이 SECURITIES이므로 CARD도 함께 실행해도 되고, 기본 배지만으로 runtime 선택·실행 증거가 완성된다.
왜 틀리나 W25 계약은 실제 사용자 근거가 있는 선택 트랙 하나와 반대 트랙 leak 부재를 요구한다.
바르게 읽기 기본 선택은 SECURITIES(증권)이며 명시적 CARD 선택은 덮어쓰기다. 실행 전 최종 선택 한 개를 selected-track.csv·근거·state에 같은 값으로 고정한다.
반례 SECURITIES 기본 배지만 보고 test 실행을 주장하거나 두 트랙 test가 함께 보이면 선택 경계를 위반한다.
❌ progressive_contract Green이면 manifest의 finalState 10_000도 증명된다.
왜 틀리나 packaged test는 1_000에서 300을 처리한 700/300만 assert한다.
바르게 읽기 10_000 finalState는 별도 learner test 또는 사람이 결박한 evidence로 증명한다.
반례 runtime은 domainContract.finalState 문자열을 parse하거나 assert하지 않는다.
❌ history에 XML SHA가 있으니 Red·Green·Cumulative XML 원본이 모두 보존됐다.
왜 틀리나 다음 cleanTest가 build/test-results의 이전 XML을 덮어쓰며 state는 bytes를 복사하지 않는다.
바르게 읽기 각 phase 직후 고유 evidence 경로로 원자 복사하고 hash를 history와 대조한다.
반례 RecordGreen 뒤에는 Red XML 경로가 사라질 수 있다.
❌ Review가 새 test를 실행해 CumulativeGreen을 다시 만들고 Q41·sealed official 결과까지 자동 확인한다.
왜 틀리나 Review는 기존 CumulativeGreen을 전제로 review entry와 leak check만 기록한다. Q41은 별도 PostgreSQL 과제이고 sealed official status는 user-attested다.
바르게 읽기 Review에서는 reviewedPhase와 history 증가만 보고, Q41 native evidence와 USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED sealed evidence를 별도로 판정한다.
반례 Review 뒤 phase는 여전히 CumulativeGreen이고 새 execution/XML·Q41 transcript·official login verification이 생기지 않는다.
STEP 11 / 13
이 코드가 보장하지 않는 것
선택 미결정·10_000 finalState·XML 보존·Review/Q41/sealed official truth처럼 이 코드가 책임지지 않는 일을 분리합니다.
reference와 learner root는 서로 달라야 한다
이 책임을 맡는 곳: runtime Gate기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
이 책임을 맡는 곳: external/human review이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
이 책임을 맡는 곳: release manifestwrapper 자체는 manifest나 JUnit XML을 판정하지 않는다
이 책임을 맡는 곳: 운영 환경증명하지 않는 범위 — apply-track-learning-stage.ps1 — 7단계의 단일 진입점
-
native exit가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 서로 다른 reference/learner root와 W25 phase를 fail-closed Python runtime에 전달한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘reference와 learner root는 서로 달라야 한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 native exit와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 12 / 13
직접 다시 써보기
뜻 → 조각 → 전체 코드 순서로 다시 씁니다.
1단계 · 뜻부터 복원
- 서로 다른 reference/learner root와 W25 phase를 fail-closed Python runtime에 전달한다.
- 핵심 값은 Week=25, Prepare→Review, TimeoutSeconds=1200, distinct roots, native exit다.
2단계 · 코드 조각 재조립
- 1. PowerShell script가 받을 입력 계약을 연다
- 2. 이 인자가 빠지면 실행 시작 전에 binding을 거절한다
- 3. 이 인자가 빠지면 실행 시작 전에 binding을 거절한다
- 4. 이 인자가 빠지면 실행 시작 전에 binding을 거절한다
- 5. 이 인자가 빠지면 실행 시작 전에 binding을 거절한다
- 6. starter canonical/raw hash만 검증하고 Gradle은 실행하지 않는 phase다
- 7. apply-track-learning-stage.ps1의 다음 검증 또는 설명 단계를 구성한다
- 8. apply-track-learning-stage.ps1의 다음 검증 또는 설명 단계를 구성한다
3단계 · 파일 전체 다시 쓰기
scripts/apply-track-learning-stage.ps1을 새 파일에 다시 쓰고 expected·actual·실패·cleanup·비범위를 주석으로 표시한다.
자가 점검
- 비어 있지 않은 모든 source 줄을 한 번씩 읽었나?
- 기본 트랙을 SECURITIES(증권) 하나로 두고 기본 선택·selected-track evidence·runtime Green을 서로 분리했나?
- Review·Q41·USER_ATTESTED sealed 상태를 자동 성공으로 꾸미지 않았나?
- XML bytes archive와 첫 실패·cleanup 책임을 설명할 수 있나?
STEP 13 / 13
전체 원본 source
감사로 고정한 전체 source를 가감 없이 확인합니다.
원문 정본 전체 source 확인하기
param(
[Parameter(Mandatory=$true)][string]$ReferenceRoot,
[Parameter(Mandatory=$true)][string]$LearnerRoot,
[Parameter(Mandatory=$true)][ValidateRange(25,38)][int]$Week,
[Parameter(Mandatory=$true)]
[ValidateSet('Prepare','VerifyStarter','RecordRed','VerifySolution','RecordGreen','Cumulative','Review')]
[string]$Phase,
[ValidateRange(1,7200)][int]$TimeoutSeconds=1200,
[string]$Python=''
)
$ErrorActionPreference='Stop'
$reference=(Resolve-Path -LiteralPath $ReferenceRoot -ErrorAction Stop).Path
$learner=(Resolve-Path -LiteralPath $LearnerRoot -ErrorAction Stop).Path
if([string]::Equals($reference,$learner,[StringComparison]::OrdinalIgnoreCase)){
throw 'ReferenceRoot and LearnerRoot must be different directories'
}
$tool=Join-Path $reference 'scripts/track_progressive_runtime.py'
if(!(Test-Path -LiteralPath $tool -PathType Leaf)){throw "runtime missing: $tool"}
if([string]::IsNullOrWhiteSpace($Python)){
$py=Get-Command py -ErrorAction SilentlyContinue
if($null-ne$py){$command=$py.Source;$prefix=@('-3')}
else{
$pythonCommand=Get-Command python -ErrorAction Stop
$command=$pythonCommand.Source;$prefix=@()
}
}else{$command=$Python;$prefix=@()}
& $command @prefix -B $tool --reference-root $reference --learner-root $learner --week $Week --phase $Phase --timeout-seconds $TimeoutSeconds
if($LASTEXITCODE-ne 0){throw "track stage failed: W${Week} phase=$Phase exit=$LASTEXITCODE"}
02verify-track-learner-proof.ps1 — test 실행 phase만 허용하는 보조 forwarder
scripts/verify-track-learner-proof.ps1
패키지 정본 보조 계약 · exact PowerShell bytes · 정본 · W25-F0213줄 연결13줄 번역2 chunks
verify-track-learner-proof.ps1 — test 실행 phase만 허용하는 보조 forwarder
scripts/verify-track-learner-proof.ps1
패키지 정본 보조 계약 · exact PowerShell bytes · 정본 · W25-F02STEP 01 / 13
오늘 이 코드에서 해결할 문제
무엇을 이해해야 하는지 질문부터 잡습니다.
RecordRed·RecordGreen·Cumulative만 apply wrapper에 전달해 native proof 실패를 PowerShell 실패로 올린다.
- RecordRed은 어느 source와 실제 결과에서 확인해야 할까?
- 첫 실패를 만드는 조건과 fail-closed 지점은 어디일까?
- 왜 ‘reference와 learner root는 서로 달라야 한다’를 별도 경계로 남겨야 할까?
RecordRedRecordGreenCumulativenative exitWeek=25왜 필요한가 — verify-track-learner-proof.ps1 — test 실행 phase만 허용하는 보조 forwarder
-
RecordRed가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 RecordRed·RecordGreen·Cumulative만 apply wrapper에 전달해 native proof 실패를 PowerShell 실패로 올린다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘reference와 learner root는 서로 달라야 한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 RecordRed와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 02 / 13
아주 짧게: 이 코드는 왜 필요할까?
웹소설 대신 이 코드가 필요한 이유만 두 문단으로 쉽게 봅니다.
사용자의 기본 선택에 따라 이 HTML은 SECURITIES(증권)을 주 트랙으로 읽는다. CARD는 비교용이며 명시적으로 고르면 기본값을 덮어쓸 수 있다. 실제 실행은 최종 선택 한 개를 selected-track.csv·근거·state에 같은 값으로 기록하고 reference와 learner 폴더를 분리한 뒤에만 시작한다. 이 HTML 자체는 Gradle/JUnit을 실행하지 않아 NOT_RUN 상태다.
한 통장만 골라 빨강에서 초록까지 증명하는 일주일
이 파일은 RecordRed·RecordGreen·Cumulative만 apply wrapper에 전달해 native proof 실패를 PowerShell 실패로 올린다. 눈으로 읽을 때는 각 줄을 검수표 한 칸처럼 보고, 입력과 다음 상태를 놓치지 않는다.
마지막 도장은 hash 확인, 세 test phase의 실제 JUnit 실행, XML bytes archive, 사람 review를 서로 구분한 뒤에만 찍는다. Review는 새 test가 아니며 Q41은 stage runtime 밖의 별도 NOT_RUN 과제, sealed official status는 USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED다. 특히 reference와 learner root는 서로 달라야 한다
딱 여기까지만 비유와 SECURITIES 기본 배지는 실제 selected-track 근거, Gradle/JUnit 실행, XML bytes 보존, 사람 review, Q41 실행, sealed official 확인을 대신하지 않는다.
STEP 03 / 13
초등학생도 이해하는 설명
생활 비유와 실제 코드의 경계를 함께 확인합니다.
값 1: RecordRed
이 파일에서 계속 확인할 고정 단서가 RecordRed다.
- 코드 연결
F02 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- reference와 learner root는 서로 달라야 한다
값 2: RecordGreen
이 파일에서 계속 확인할 고정 단서가 RecordGreen다.
- 코드 연결
F02 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
값 3: Cumulative
이 파일에서 계속 확인할 고정 단서가 Cumulative다.
- 코드 연결
F02 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
값 4: native exit
이 파일에서 계속 확인할 고정 단서가 native exit다.
- 코드 연결
F02 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- W25 PDF의 공식 진입점은 apply-track-learning-stage.ps1이다
값 5: Week=25
이 파일에서 계속 확인할 고정 단서가 Week=25다.
- 코드 연결
F02 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- reference와 learner root는 서로 달라야 한다
STEP 04 / 13
비유 ↔ 코드 전체 연결표
감사 규칙상 연결 대상인 원본 13줄을 빠짐없이 연결합니다.
| 줄 | 정확한 원본 줄 | STARRY 비유 | 실제 뜻·입력·결과·한계 |
|---|---|---|---|
| 1줄F02-L01 | param( |
출고표 1번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 PowerShell script가 받을 입력 계약을 연다.
|
| 2줄F02-L02 | [ |
출고표 2번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 이 인자가 빠지면 실행 시작 전에 binding을 거절한다.
|
| 3줄F02-L03 | [ |
출고표 3번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 이 인자가 빠지면 실행 시작 전에 binding을 거절한다.
|
| 4줄F02-L04 | [ |
출고표 4번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 이 인자가 빠지면 실행 시작 전에 binding을 거절한다.
|
| 5줄F02-L05 | [ |
출고표 5번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 선택 트랙 test 하나의 의도한 실패와 Red marker를 기록하는 phase다.
|
| 6줄F02-L06 | [ |
출고표 6번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 verify-track-learner-proof.ps1의 다음 검증 또는 설명 단계를 구성한다.
|
| 7줄F02-L07 | [ |
출고표 7번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 verify-track-learner-proof.ps1의 다음 검증 또는 설명 단계를 구성한다.
|
| 8줄F02-L08 | ) |
출고표 8번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 9줄F02-L09 | $ErrorActionPreference= |
출고표 9번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 PowerShell 오류를 계속 진행하지 않고 중단시키는 기본 정책을 둔다.
|
| 10줄F02-L10 | $runner= |
출고표 10번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 입력 경로를 실제 절대 경로로 확인한다.
|
| 11줄F02-L11 | & powershell. |
출고표 11번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 verify-track-learner-proof.ps1의 다음 검증 또는 설명 단계를 구성한다.
|
| 12줄F02-L12 | -ReferenceRoot $ReferenceRoot -LearnerRoot $LearnerRoot -Week $Week -Phase $Phase -TimeoutSeconds $TimeoutSeconds -Python $Python |
출고표 12번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 verify-track-learner-proof.ps1의 다음 검증 또는 설명 단계를 구성한다.
|
| 13줄F02-L13 | if( |
출고표 13번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 native process 종료 코드를 검사해 실패를 놓치지 않는다.
|
STEP 05 / 13
원본 코드 조각
원본을 2개 의미 조각으로 나누어 그대로 확인합니다.
파일을 한꺼번에 외우지 않고 실행 의미가 이어지는 작은 조각으로 봅니다. 아래 코드는 hash로 고정한 native 정본 source에서 그대로 잘랐습니다.
param(
[Parameter(Mandatory=$true)][string]$ReferenceRoot,
[Parameter(Mandatory=$true)][string]$LearnerRoot,
[Parameter(Mandatory=$true)][ValidateRange(25,38)][int]$Week,
[Parameter(Mandatory=$true)][ValidateSet('RecordRed','RecordGreen','Cumulative')][string]$Phase,
[ValidateRange(1,7200)][int]$TimeoutSeconds=1200,
[string]$Python=''
)
$ErrorActionPreference='Stop'
$runner=Join-Path (Resolve-Path -LiteralPath $ReferenceRoot).Path 'scripts/apply-track-learning-stage.ps1'
& powershell.exe -NoProfile -ExecutionPolicy Bypass -File $runner `
-ReferenceRoot $ReferenceRoot -LearnerRoot $LearnerRoot -Week $Week -Phase $Phase -TimeoutSeconds $TimeoutSeconds -Python $Python
if($LASTEXITCODE-ne 0){throw "native track proof failed: W${Week} phase=$Phase exit=$LASTEXITCODE"}
STEP 06 / 13
코드 한 줄씩 한국어로 번역
비어 있지 않은 13줄을 모두 한국어로 옮깁니다.
비어 있지 않은 원본 줄은 하나도 생략하지 않습니다.
| 줄 | 원본 | 한국어 번역 |
|---|---|---|
| 1 | param( | 실행 의미: PowerShell script가 받을 입력 계약을 연다. |
| 2 | [Parameter(Mandatory=$true)][string]$ReferenceRoot, | 실행 의미: 이 인자가 빠지면 실행 시작 전에 binding을 거절한다. |
| 3 | [Parameter(Mandatory=$true)][string]$LearnerRoot, | 실행 의미: 이 인자가 빠지면 실행 시작 전에 binding을 거절한다. |
| 4 | [Parameter(Mandatory=$true)][ValidateRange(25,38)][int]$Week, | 실행 의미: 이 인자가 빠지면 실행 시작 전에 binding을 거절한다. |
| 5 | [Parameter(Mandatory=$true)][ValidateSet('RecordRed','RecordGreen','Cumulative')][string]$Phase, | 실행 의미: 선택 트랙 test 하나의 의도한 실패와 Red marker를 기록하는 phase다. |
| 6 | [ValidateRange(1,7200)][int]$TimeoutSeconds=1200, | 실행 의미: verify-track-learner-proof.ps1의 다음 검증 또는 설명 단계를 구성한다. |
| 7 | [string]$Python='' | 실행 의미: verify-track-learner-proof.ps1의 다음 검증 또는 설명 단계를 구성한다. |
| 8 | ) | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 9 | $ErrorActionPreference='Stop' | 실행 의미: PowerShell 오류를 계속 진행하지 않고 중단시키는 기본 정책을 둔다. |
| 10 | $runner=Join-Path (Resolve-Path -LiteralPath $ReferenceRoot).Path 'scripts/apply-track-learning-stage.ps1' | 실행 의미: 입력 경로를 실제 절대 경로로 확인한다. |
| 11 | & powershell.exe -NoProfile -ExecutionPolicy Bypass -File $runner ` | 실행 의미: verify-track-learner-proof.ps1의 다음 검증 또는 설명 단계를 구성한다. |
| 12 | -ReferenceRoot $ReferenceRoot -LearnerRoot $LearnerRoot -Week $Week -Phase $Phase -TimeoutSeconds $TimeoutSeconds -Python $Python | 실행 의미: verify-track-learner-proof.ps1의 다음 검증 또는 설명 단계를 구성한다. |
| 13 | if($LASTEXITCODE-ne 0){throw "native track proof failed: W${Week} phase=$Phase exit=$LASTEXITCODE"} | 실행 의미: native process 종료 코드를 검사해 실패를 놓치지 않는다. |
STEP 07 / 13
기존 수준의 한 줄 읽기·문법 해부
쉬운 설명 다음에 문법과 실행 순서를 정밀하게 읽습니다.
한 줄로 읽기verify-track-learner-proof.ps1 — test 실행 phase만 허용하는 보조 forwarder는 RecordRed·RecordGreen·Cumulative만 apply wrapper에 전달해 native proof 실패를 PowerShell 실패로 올린다.
문법 해부
- .ps1 문법에서 선언·조건·pipeline·block 경계를 먼저 나눈다.
- manifest의 finalState와 packaged progressive test의 1_000→700/300 oracle을 서로 다른 계약으로 읽는다.
- phase state·native exit·JUnit XML hash·보존된 XML bytes·사람 판정·USER_ATTESTED external status를 서로 대체하지 않는다.
실행 순서
- 기본 트랙은 SECURITIES(증권)이며, 명시적 CARD 선택은 기본값을 덮어쓴다. 실제 실행 전 최종 선택 한 개를 selected-track.csv·근거·state에 같은 값으로 기록하고 서로 다른 reference/learner root를 확인한다.
- Prepare→VerifyStarter→RecordRed→VerifySolution→RecordGreen→Cumulative→Review 순서를 지킨다.
- test를 소유한 세 phase에서만 native exit와 exact JUnit XML 수치를 판정한다.
- 다음 cleanTest 전에 XML bytes를 고유 경로에 보존하고 runtime history hash와 다시 묶는다. Review·Q41·sealed official evidence는 각자의 별도 owner와 검증 수준으로 남긴다.
W25 조각별 정밀 해설
F02-C01 · 원문 1–12줄
- 문법 해부
- .ps1 문법으로 1–12줄의 선언·조건·phase·assert block을 나눈다.
- 실제 값 추적
- RecordRed, RecordGreen, Cumulative를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- 기본 SECURITIES 또는 명시적으로 덮어쓴 CARD 중 최종 선택 한 개의 selected-track evidence와 runtime 결과에서 expected와 actual이 일치하고 owner evidence가 같은 run/hash 및 보존 XML에 연결되는 경우다. 기본/덮어쓰기 표시만 있고 실행 evidence가 없으면 NOT_RUN이다.
- 틀린 예·반례
- reference와 learner root는 서로 달라야 한다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- phase 이름·manifest finalState·history hash·exit0 하나를 W25 증거 전체와 같다고 보지 않는다.
- 하지 않는 일
- reference와 learner root는 서로 달라야 한다; 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다; 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다; W25 PDF의 공식 진입점은 apply-track-learning-stage.ps1이다
- 다음 연결
- 다음 조각 또는 F02 evidence 판정으로 상태를 넘긴다.
F02-C02 · 원문 13–13줄
- 문법 해부
- .ps1 문법으로 13–13줄의 선언·조건·phase·assert block을 나눈다.
- 실제 값 추적
- RecordRed, RecordGreen, Cumulative를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- 기본 SECURITIES 또는 명시적으로 덮어쓴 CARD 중 최종 선택 한 개의 selected-track evidence와 runtime 결과에서 expected와 actual이 일치하고 owner evidence가 같은 run/hash 및 보존 XML에 연결되는 경우다. 기본/덮어쓰기 표시만 있고 실행 evidence가 없으면 NOT_RUN이다.
- 틀린 예·반례
- reference와 learner root는 서로 달라야 한다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- phase 이름·manifest finalState·history hash·exit0 하나를 W25 증거 전체와 같다고 보지 않는다.
- 하지 않는 일
- reference와 learner root는 서로 달라야 한다; 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다; 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다; W25 PDF의 공식 진입점은 apply-track-learning-stage.ps1이다
- 다음 연결
- 다음 조각 또는 F02 evidence 판정으로 상태를 넘긴다.
실행 순서 — verify-track-learner-proof.ps1 — test 실행 phase만 허용하는 보조 forwarder
-
RecordGreen가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 RecordRed·RecordGreen·Cumulative만 apply wrapper에 전달해 native proof 실패를 PowerShell 실패로 올린다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 RecordGreen와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 08 / 13
실제 값 따라가기
같은 입력값이 어느 줄을 지나 어떤 결과가 되는지 추적합니다.
| 순서 | 들어온 값 | 코드가 하는 일 | 나온 값·상태 | 경계 |
|---|---|---|---|---|
| 입력 | RecordRed | source 계약에 대입 | F02 실행/설명 시작 상태 | reference와 learner root는 서로 달라야 한다 |
| 검증 | RecordGreen | expected와 actual 또는 형식 대조 | 통과 또는 첫 mismatch | 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다 |
| 증거 | Week=25 | marker·hash·row를 같은 run에 연결 | 범위가 적힌 evidence 후보 | W25 PDF의 공식 진입점은 apply-track-learning-stage.ps1이다 |
실제 값 — verify-track-learner-proof.ps1 — test 실행 phase만 허용하는 보조 forwarder
-
Cumulative가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 RecordRed·RecordGreen·Cumulative만 apply wrapper에 전달해 native proof 실패를 PowerShell 실패로 올린다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 Cumulative와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 09 / 13
Gradle·JUnit XML·PowerShell·SQL 내부에서 벌어지는 일
세 test phase, XML bytes archive, Review, 별도 Q41, USER_ATTESTED sealed 결과의 owner와 증명 범위를 구분합니다.
verify-track-learner-proof.ps1 bytes와 track·phase·hash 계약을 읽는다.
SECURITIES 기본 선택과 파일 존재·phase 이름만으로 runtime Green을 주장할 수 없다. 실제 selected-track evidence와 실행 결과는 별도다.RecordRed·RecordGreen·Cumulative에서만 native exit와 exact JUnit XML을 만든다.
reference와 learner root는 서로 달라야 한다XML bytes를 고유 파일로 보존하고 history hash와 묶은 뒤, Review는 기존 CumulativeGreen만 인용한다. Q41은 별도 PostgreSQL evidence, sealed official status는 user-attested evidence로 남긴다.
W25 PDF의 공식 진입점은 apply-track-learning-stage.ps1이다첫 실패 경계 — verify-track-learner-proof.ps1 — test 실행 phase만 허용하는 보조 forwarder
-
native exit가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 RecordRed·RecordGreen·Cumulative만 apply wrapper에 전달해 native proof 실패를 PowerShell 실패로 올린다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘W25 PDF의 공식 진입점은 apply-track-learning-stage.ps1이다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 native exit와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 10 / 13
흔한 착각과 틀린 예
그럴듯하지만 틀린 해석을 반례로 고칩니다.
❌ Prepare·VerifyStarter·VerifySolution·Review도 Gradle을 실행해 Green을 만든다.
왜 틀리나 runtime에서 test 실행을 소유하는 phase는 RecordRed·RecordGreen·Cumulative뿐이다.
바르게 읽기 각 phase history의 execution 유무와 mode를 직접 확인한다.
반례 VerifySolution은 solution hash만 검증하므로 새 JUnit XML이 없어야 정상이다.
❌ 기본 트랙이 SECURITIES이므로 CARD도 함께 실행해도 되고, 기본 배지만으로 runtime 선택·실행 증거가 완성된다.
왜 틀리나 W25 계약은 실제 사용자 근거가 있는 선택 트랙 하나와 반대 트랙 leak 부재를 요구한다.
바르게 읽기 기본 선택은 SECURITIES(증권)이며 명시적 CARD 선택은 덮어쓰기다. 실행 전 최종 선택 한 개를 selected-track.csv·근거·state에 같은 값으로 고정한다.
반례 SECURITIES 기본 배지만 보고 test 실행을 주장하거나 두 트랙 test가 함께 보이면 선택 경계를 위반한다.
❌ progressive_contract Green이면 manifest의 finalState 10_000도 증명된다.
왜 틀리나 packaged test는 1_000에서 300을 처리한 700/300만 assert한다.
바르게 읽기 10_000 finalState는 별도 learner test 또는 사람이 결박한 evidence로 증명한다.
반례 runtime은 domainContract.finalState 문자열을 parse하거나 assert하지 않는다.
❌ history에 XML SHA가 있으니 Red·Green·Cumulative XML 원본이 모두 보존됐다.
왜 틀리나 다음 cleanTest가 build/test-results의 이전 XML을 덮어쓰며 state는 bytes를 복사하지 않는다.
바르게 읽기 각 phase 직후 고유 evidence 경로로 원자 복사하고 hash를 history와 대조한다.
반례 RecordGreen 뒤에는 Red XML 경로가 사라질 수 있다.
❌ Review가 새 test를 실행해 CumulativeGreen을 다시 만들고 Q41·sealed official 결과까지 자동 확인한다.
왜 틀리나 Review는 기존 CumulativeGreen을 전제로 review entry와 leak check만 기록한다. Q41은 별도 PostgreSQL 과제이고 sealed official status는 user-attested다.
바르게 읽기 Review에서는 reviewedPhase와 history 증가만 보고, Q41 native evidence와 USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED sealed evidence를 별도로 판정한다.
반례 Review 뒤 phase는 여전히 CumulativeGreen이고 새 execution/XML·Q41 transcript·official login verification이 생기지 않는다.
STEP 11 / 13
이 코드가 보장하지 않는 것
선택 미결정·10_000 finalState·XML 보존·Review/Q41/sealed official truth처럼 이 코드가 책임지지 않는 일을 분리합니다.
reference와 learner root는 서로 달라야 한다
이 책임을 맡는 곳: runtime Gate기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
이 책임을 맡는 곳: external/human review이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
이 책임을 맡는 곳: release manifestW25 PDF의 공식 진입점은 apply-track-learning-stage.ps1이다
이 책임을 맡는 곳: 운영 환경증명하지 않는 범위 — verify-track-learner-proof.ps1 — test 실행 phase만 허용하는 보조 forwarder
-
Week=25가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 RecordRed·RecordGreen·Cumulative만 apply wrapper에 전달해 native proof 실패를 PowerShell 실패로 올린다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘reference와 learner root는 서로 달라야 한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 Week=25와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 12 / 13
직접 다시 써보기
뜻 → 조각 → 전체 코드 순서로 다시 씁니다.
1단계 · 뜻부터 복원
- RecordRed·RecordGreen·Cumulative만 apply wrapper에 전달해 native proof 실패를 PowerShell 실패로 올린다.
- 핵심 값은 RecordRed, RecordGreen, Cumulative, native exit, Week=25다.
2단계 · 코드 조각 재조립
- 1. PowerShell script가 받을 입력 계약을 연다
- 2. 이 인자가 빠지면 실행 시작 전에 binding을 거절한다
- 3. 이 인자가 빠지면 실행 시작 전에 binding을 거절한다
- 4. 이 인자가 빠지면 실행 시작 전에 binding을 거절한다
- 5. 선택 트랙 test 하나의 의도한 실패와 Red marker를 기록하는 phase다
- 6. verify-track-learner-proof.ps1의 다음 검증 또는 설명 단계를 구성한다
- 7. verify-track-learner-proof.ps1의 다음 검증 또는 설명 단계를 구성한다
- 8. 앞에서 연 block 또는 호출 범위를 닫는다
3단계 · 파일 전체 다시 쓰기
scripts/verify-track-learner-proof.ps1을 새 파일에 다시 쓰고 expected·actual·실패·cleanup·비범위를 주석으로 표시한다.
자가 점검
- 비어 있지 않은 모든 source 줄을 한 번씩 읽었나?
- 기본 트랙을 SECURITIES(증권) 하나로 두고 기본 선택·selected-track evidence·runtime Green을 서로 분리했나?
- Review·Q41·USER_ATTESTED sealed 상태를 자동 성공으로 꾸미지 않았나?
- XML bytes archive와 첫 실패·cleanup 책임을 설명할 수 있나?
STEP 13 / 13
전체 원본 source
감사로 고정한 전체 source를 가감 없이 확인합니다.
원문 정본 전체 source 확인하기
param(
[Parameter(Mandatory=$true)][string]$ReferenceRoot,
[Parameter(Mandatory=$true)][string]$LearnerRoot,
[Parameter(Mandatory=$true)][ValidateRange(25,38)][int]$Week,
[Parameter(Mandatory=$true)][ValidateSet('RecordRed','RecordGreen','Cumulative')][string]$Phase,
[ValidateRange(1,7200)][int]$TimeoutSeconds=1200,
[string]$Python=''
)
$ErrorActionPreference='Stop'
$runner=Join-Path (Resolve-Path -LiteralPath $ReferenceRoot).Path 'scripts/apply-track-learning-stage.ps1'
& powershell.exe -NoProfile -ExecutionPolicy Bypass -File $runner `
-ReferenceRoot $ReferenceRoot -LearnerRoot $LearnerRoot -Week $Week -Phase $Phase -TimeoutSeconds $TimeoutSeconds -Python $Python
if($LASTEXITCODE-ne 0){throw "native track proof failed: W${Week} phase=$Phase exit=$LASTEXITCODE"}
03SECURITIES manifest — 현금 available+reserved 불변식
track_learning_stages/securities/w25/manifest.json
패키지 정본 보조 계약 · exact W25 manifest bytes · 정본 · W25-F0343줄 연결43줄 번역4 chunks
SECURITIES manifest — 현금 available+reserved 불변식
track_learning_stages/securities/w25/manifest.json
패키지 정본 보조 계약 · exact W25 manifest bytes · 정본 · W25-F03STEP 01 / 13
오늘 이 코드에서 해결할 문제
무엇을 이해해야 하는지 질문부터 잡습니다.
선택 트랙 selector·redMarker·starter/solution hash와 0/10_000 설명 계약을 고정한다.
- SECURITIES은 어느 source와 실제 결과에서 확인해야 할까?
- 첫 실패를 만드는 조건과 fail-closed 지점은 어디일까?
- 왜 ‘manifest 문자열은 실행 결과가 아니다’를 별도 경계로 남겨야 할까?
SECURITIESprogressive_contractW25_SECURITIES_RED_EXPECTEDavailable=0,reserved=10_000LEARNER_AUTHORED왜 필요한가 — SECURITIES manifest — 현금 available+reserved 불변식
-
SECURITIES가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 선택 트랙 selector·redMarker·starter/solution hash와 0/10_000 설명 계약을 고정한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘manifest 문자열은 실행 결과가 아니다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 SECURITIES와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 02 / 13
아주 짧게: 이 코드는 왜 필요할까?
웹소설 대신 이 코드가 필요한 이유만 두 문단으로 쉽게 봅니다.
사용자의 기본 선택에 따라 이 HTML은 SECURITIES(증권)을 주 트랙으로 읽는다. CARD는 비교용이며 명시적으로 고르면 기본값을 덮어쓸 수 있다. 실제 실행은 최종 선택 한 개를 selected-track.csv·근거·state에 같은 값으로 기록하고 reference와 learner 폴더를 분리한 뒤에만 시작한다. 이 HTML 자체는 Gradle/JUnit을 실행하지 않아 NOT_RUN 상태다.
한 통장만 골라 빨강에서 초록까지 증명하는 일주일
이 파일은 선택 트랙 selector·redMarker·starter/solution hash와 0/10_000 설명 계약을 고정한다. 눈으로 읽을 때는 각 줄을 검수표 한 칸처럼 보고, 입력과 다음 상태를 놓치지 않는다.
마지막 도장은 hash 확인, 세 test phase의 실제 JUnit 실행, XML bytes archive, 사람 review를 서로 구분한 뒤에만 찍는다. Review는 새 test가 아니며 Q41은 stage runtime 밖의 별도 NOT_RUN 과제, sealed official status는 USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED다. 특히 manifest 문자열은 실행 결과가 아니다
딱 여기까지만 비유와 SECURITIES 기본 배지는 실제 selected-track 근거, Gradle/JUnit 실행, XML bytes 보존, 사람 review, Q41 실행, sealed official 확인을 대신하지 않는다.
STEP 03 / 13
초등학생도 이해하는 설명
생활 비유와 실제 코드의 경계를 함께 확인합니다.
값 1: SECURITIES
이 파일에서 계속 확인할 고정 단서가 SECURITIES다.
- 코드 연결
F03 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- manifest 문자열은 실행 결과가 아니다
값 2: progressive_contract
이 파일에서 계속 확인할 고정 단서가 progressive_contract다.
- 코드 연결
F03 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- packaged test는 1_000→700/300만 assert한다
값 3: W25_SECURITIES_RED_EXPECTED
이 파일에서 계속 확인할 고정 단서가 W25_SECURITIES_RED_EXPECTED다.
- 코드 연결
F03 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- finalState 10_000은 별도 evidence가 필요하다
값 4: available=0,reserved=10_000
이 파일에서 계속 확인할 고정 단서가 available=0,reserved=10_000다.
- 코드 연결
F03 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- reference와 learner root는 서로 달라야 한다
값 5: LEARNER_AUTHORED
이 파일에서 계속 확인할 고정 단서가 LEARNER_AUTHORED다.
- 코드 연결
F03 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
STEP 04 / 13
비유 ↔ 코드 전체 연결표
감사 규칙상 연결 대상인 원본 43줄을 빠짐없이 연결합니다.
| 줄 | 정확한 원본 줄 | STARRY 비유 | 실제 뜻·입력·결과·한계 |
|---|---|---|---|
| 1줄F03-L01 | { |
출고표 1번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 2줄F03-L02 | "schemaVersion": |
출고표 2번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 manifest 형식 버전을 2로 고정한다.
|
| 3줄F03-L03 | "week": |
출고표 3번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 이 계약이 W25에만 적용됨을 숫자로 고정한다.
|
| 4줄F03-L04 | "track": |
출고표 4번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 이 manifest의 SECURITIES 또는 CARD 분기 identity를 고정할 뿐 실제 사용자 선택을 대신하지 않는다.
|
| 5줄F03-L05 | "title": |
출고표 5번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 manifest.json의 다음 검증 또는 설명 단계를 구성한다.
|
| 6줄F03-L06 | "claim": |
출고표 6번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 manifest.json의 다음 검증 또는 설명 단계를 구성한다.
|
| 7줄F03-L07 | "textEncoding": |
출고표 7번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 manifest.json의 다음 검증 또는 설명 단계를 구성한다.
|
| 8줄F03-L08 | "newlinePolicy": |
출고표 8번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 manifest.json의 다음 검증 또는 설명 단계를 구성한다.
|
| 9줄F03-L09 | "domainContract": |
출고표 9번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 불변식·실패 모드·최종 상태처럼 도메인 설명을 한 묶음으로 연다.
|
| 10줄F03-L10 | "invariant": |
출고표 10번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 두 잔액의 합계 보존과 음수 금지라는 핵심 불변식을 설명한다.
|
| 11줄F03-L11 | "failureMode": |
출고표 11번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 차감 또는 증가 누락이 같은 돈·한도의 중복 사용으로 이어짐을 밝힌다.
|
| 12줄F03-L12 | "implementationTarget": |
출고표 12번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 manifest.json의 다음 검증 또는 설명 단계를 구성한다.
|
| 13줄F03-L13 | "finalState": |
출고표 13번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 PDF가 요구하는 10_000 시나리오를 설명용 계약에 고정하며 packaged 1_000→700/300 test의 자동 assertion과 분리한다.
|
| 14줄F03-L14 | "recoveryFocus": |
출고표 14번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 manifest.json의 다음 검증 또는 설명 단계를 구성한다.
|
| 15줄F03-L15 | "interviewDefense": |
출고표 15번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 manifest.json의 다음 검증 또는 설명 단계를 구성한다.
|
| 16줄F03-L16 | }, |
출고표 16번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 manifest.json의 다음 검증 또는 설명 단계를 구성한다.
|
| 17줄F03-L17 | "selector": |
출고표 17번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 선택 트랙의 정확한 JUnit suite 이름 하나를 지정한다.
|
| 18줄F03-L18 | "testMethod": |
출고표 18번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 progressive_contract 메서드 하나를 W25 proof 대상으로 지정한다.
|
| 19줄F03-L19 | "redMarker": |
출고표 19번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 의도한 Red 실패를 다른 실패와 구분할 marker를 고정한다.
|
| 20줄F03-L20 | "predecessor": |
출고표 20번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 manifest.json의 다음 검증 또는 설명 단계를 구성한다.
|
| 21줄F03-L21 | "providedFiles": |
출고표 21번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 manifest.json의 다음 검증 또는 설명 단계를 구성한다.
|
| 22줄F03-L22 | "testFiles": |
출고표 22번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 manifest.json의 다음 검증 또는 설명 단계를 구성한다.
|
| 23줄F03-L23 | { |
출고표 23번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 24줄F03-L24 | "learnerPath": |
출고표 24번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 manifest.json의 다음 검증 또는 설명 단계를 구성한다.
|
| 25줄F03-L25 | "asset": |
출고표 25번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 manifest.json의 다음 검증 또는 설명 단계를 구성한다.
|
| 26줄F03-L26 | "introducedAt": |
출고표 26번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 manifest.json의 다음 검증 또는 설명 단계를 구성한다.
|
| 27줄F03-L27 | "ownership": |
출고표 27번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 manifest.json의 다음 검증 또는 설명 단계를 구성한다.
|
| 28줄F03-L28 | "sha256": |
출고표 28번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 현재 bytes를 64자리 digest로 evidence에 결박한다.
|
| 29줄F03-L29 | "canonicalTextSha256": |
출고표 29번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 현재 bytes를 64자리 digest로 evidence에 결박한다.
|
| 30줄F03-L30 | } |
출고표 30번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 31줄F03-L31 | ], |
출고표 31번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 manifest.json의 다음 검증 또는 설명 단계를 구성한다.
|
| 32줄F03-L32 | "authoredTarget": |
출고표 32번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 학습자가 직접 소유하는 main Java 경로와 starter/solution hash를 묶는다.
|
| 33줄F03-L33 | "learnerPath": |
출고표 33번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 manifest.json의 다음 검증 또는 설명 단계를 구성한다.
|
| 34줄F03-L34 | "introducedAt": |
출고표 34번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 manifest.json의 다음 검증 또는 설명 단계를 구성한다.
|
| 35줄F03-L35 | "ownership": |
출고표 35번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 manifest.json의 다음 검증 또는 설명 단계를 구성한다.
|
| 36줄F03-L36 | "starterAsset": |
출고표 36번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 manifest.json의 다음 검증 또는 설명 단계를 구성한다.
|
| 37줄F03-L37 | "starterSha256": |
출고표 37번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 starter 원시 bytes의 SHA-256을 manifest에 결박한다.
|
| 38줄F03-L38 | "starterCanonicalTextSha256": |
출고표 38번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 현재 bytes를 64자리 digest로 evidence에 결박한다.
|
| 39줄F03-L39 | "solutionAsset": |
출고표 39번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 manifest.json의 다음 검증 또는 설명 단계를 구성한다.
|
| 40줄F03-L40 | "solutionSha256": |
출고표 40번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 solution 원시 bytes의 SHA-256을 manifest에 결박한다.
|
| 41줄F03-L41 | "solutionCanonicalTextSha256": |
출고표 41번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 현재 bytes를 64자리 digest로 evidence에 결박한다.
|
| 42줄F03-L42 | } |
출고표 42번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 43줄F03-L43 | } |
출고표 43번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
STEP 05 / 13
원본 코드 조각
원본을 4개 의미 조각으로 나누어 그대로 확인합니다.
파일을 한꺼번에 외우지 않고 실행 의미가 이어지는 작은 조각으로 봅니다. 아래 코드는 hash로 고정한 native 정본 source에서 그대로 잘랐습니다.
{
"schemaVersion": 2,
"week": 25,
"track": "SECURITIES",
"title": "현금 가용액·예약액 불변식",
"claim": "reserve 뒤 available+reserved 보존",
"textEncoding": "UTF-8",
"newlinePolicy": "LF_CANONICAL_CRLF_EQUIVALENT",
"domainContract": {
"invariant": "예약 전후 availableCash+reservedCash 합계가 보존되고 두 값은 음수가 아니다.",
"failureMode": "가용액 차감 누락으로 같은 현금을 중복 예약한다.",
"implementationTarget": "src/main/java/com/example/financialcore/securities/CashWallet.java :: 현금 가용액·예약액 불변식 :: reserve 뒤 available+reserved 보존",
"finalState": "available=0, reserved=10_000",
"recoveryFocus": "예약 전후 두 잔액과 합계를 먼저 비교한다.",
"interviewDefense": "현금 예약은 총액 보존과 음수 방지를 함께 증명해야 한다."
},
"selector": "com.example.financialcore.securities.W25CashWalletProgressiveTest",
"testMethod": "progressive_contract",
"redMarker": "W25_SECURITIES_RED_EXPECTED",
"predecessor": null,
"providedFiles": [],
"testFiles": [
{
"learnerPath": "src/test/java/com/example/financialcore/securities/W25CashWalletProgressiveTest.java",
"asset": "tests/src/test/java/com/example/financialcore/securities/W25CashWalletProgressiveTest.java",
"introducedAt": 25,
"ownership": "PROVIDED_FIXTURE_VERIFIED",
"sha256": "f45516879819dc698533b48c434ee2c374a03d150bdd834fe39501db65532312",
"canonicalTextSha256": "f45516879819dc698533b48c434ee2c374a03d150bdd834fe39501db65532312"
}
],
"authoredTarget": {
"learnerPath": "src/main/java/com/example/financialcore/securities/CashWallet.java",
"introducedAt": 25,
"ownership": "LEARNER_AUTHORED",
"starterAsset": "starter/src/main/java/com/example/financialcore/securities/CashWallet.java",
"starterSha256": "b88925eec28e4c4afb8a9438f490ddb99670c69e33b70b746ee8e1cd6ffcdd2d",
"starterCanonicalTextSha256": "b88925eec28e4c4afb8a9438f490ddb99670c69e33b70b746ee8e1cd6ffcdd2d",
"solutionAsset": "solution/src/main/java/com/example/financialcore/securities/CashWallet.java",
"solutionSha256": "cdf78c1f20d8cdbb6304d89c0d4298e65de7d4eb64b39812c37fda28f26fb411",
"solutionCanonicalTextSha256": "cdf78c1f20d8cdbb6304d89c0d4298e65de7d4eb64b39812c37fda28f26fb411"
}
}
STEP 06 / 13
코드 한 줄씩 한국어로 번역
비어 있지 않은 43줄을 모두 한국어로 옮깁니다.
비어 있지 않은 원본 줄은 하나도 생략하지 않습니다.
| 줄 | 원본 | 한국어 번역 |
|---|---|---|
| 1 | { | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 2 | "schemaVersion": 2, | 실행 의미: manifest 형식 버전을 2로 고정한다. |
| 3 | "week": 25, | 실행 의미: 이 계약이 W25에만 적용됨을 숫자로 고정한다. |
| 4 | "track": "SECURITIES", | 실행 의미: 이 manifest의 SECURITIES 또는 CARD 분기 identity를 고정할 뿐 실제 사용자 선택을 대신하지 않는다. |
| 5 | "title": "현금 가용액·예약액 불변식", | 실행 의미: manifest.json의 다음 검증 또는 설명 단계를 구성한다. |
| 6 | "claim": "reserve 뒤 available+reserved 보존", | 실행 의미: manifest.json의 다음 검증 또는 설명 단계를 구성한다. |
| 7 | "textEncoding": "UTF-8", | 실행 의미: manifest.json의 다음 검증 또는 설명 단계를 구성한다. |
| 8 | "newlinePolicy": "LF_CANONICAL_CRLF_EQUIVALENT", | 실행 의미: manifest.json의 다음 검증 또는 설명 단계를 구성한다. |
| 9 | "domainContract": { | 실행 의미: 불변식·실패 모드·최종 상태처럼 도메인 설명을 한 묶음으로 연다. |
| 10 | "invariant": "예약 전후 availableCash+reservedCash 합계가 보존되고 두 값은 음수가 아니다.", | 실행 의미: 두 잔액의 합계 보존과 음수 금지라는 핵심 불변식을 설명한다. |
| 11 | "failureMode": "가용액 차감 누락으로 같은 현금을 중복 예약한다.", | 실행 의미: 차감 또는 증가 누락이 같은 돈·한도의 중복 사용으로 이어짐을 밝힌다. |
| 12 | "implementationTarget": "src/main/java/com/example/financialcore/securities/CashWallet.java :: 현금 가용액·예약액 불변식 :: reserve 뒤 available+reserved 보존", | 실행 의미: manifest.json의 다음 검증 또는 설명 단계를 구성한다. |
| 13 | "finalState": "available=0, reserved=10_000", | 실행 의미: PDF가 요구하는 10_000 시나리오를 설명용 계약에 고정하며 packaged 1_000→700/300 test의 자동 assertion과 분리한다. |
| 14 | "recoveryFocus": "예약 전후 두 잔액과 합계를 먼저 비교한다.", | 실행 의미: manifest.json의 다음 검증 또는 설명 단계를 구성한다. |
| 15 | "interviewDefense": "현금 예약은 총액 보존과 음수 방지를 함께 증명해야 한다." | 실행 의미: manifest.json의 다음 검증 또는 설명 단계를 구성한다. |
| 16 | }, | 실행 의미: manifest.json의 다음 검증 또는 설명 단계를 구성한다. |
| 17 | "selector": "com.example.financialcore.securities.W25CashWalletProgressiveTest", | 실행 의미: 선택 트랙의 정확한 JUnit suite 이름 하나를 지정한다. |
| 18 | "testMethod": "progressive_contract", | 실행 의미: progressive_contract 메서드 하나를 W25 proof 대상으로 지정한다. |
| 19 | "redMarker": "W25_SECURITIES_RED_EXPECTED", | 실행 의미: 의도한 Red 실패를 다른 실패와 구분할 marker를 고정한다. |
| 20 | "predecessor": null, | 실행 의미: manifest.json의 다음 검증 또는 설명 단계를 구성한다. |
| 21 | "providedFiles": [], | 실행 의미: manifest.json의 다음 검증 또는 설명 단계를 구성한다. |
| 22 | "testFiles": [ | 실행 의미: manifest.json의 다음 검증 또는 설명 단계를 구성한다. |
| 23 | { | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 24 | "learnerPath": "src/test/java/com/example/financialcore/securities/W25CashWalletProgressiveTest.java", | 실행 의미: manifest.json의 다음 검증 또는 설명 단계를 구성한다. |
| 25 | "asset": "tests/src/test/java/com/example/financialcore/securities/W25CashWalletProgressiveTest.java", | 실행 의미: manifest.json의 다음 검증 또는 설명 단계를 구성한다. |
| 26 | "introducedAt": 25, | 실행 의미: manifest.json의 다음 검증 또는 설명 단계를 구성한다. |
| 27 | "ownership": "PROVIDED_FIXTURE_VERIFIED", | 실행 의미: manifest.json의 다음 검증 또는 설명 단계를 구성한다. |
| 28 | "sha256": "f45516879819dc698533b48c434ee2c374a03d150bdd834fe39501db65532312", | 실행 의미: 현재 bytes를 64자리 digest로 evidence에 결박한다. |
| 29 | "canonicalTextSha256": "f45516879819dc698533b48c434ee2c374a03d150bdd834fe39501db65532312" | 실행 의미: 현재 bytes를 64자리 digest로 evidence에 결박한다. |
| 30 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 31 | ], | 실행 의미: manifest.json의 다음 검증 또는 설명 단계를 구성한다. |
| 32 | "authoredTarget": { | 실행 의미: 학습자가 직접 소유하는 main Java 경로와 starter/solution hash를 묶는다. |
| 33 | "learnerPath": "src/main/java/com/example/financialcore/securities/CashWallet.java", | 실행 의미: manifest.json의 다음 검증 또는 설명 단계를 구성한다. |
| 34 | "introducedAt": 25, | 실행 의미: manifest.json의 다음 검증 또는 설명 단계를 구성한다. |
| 35 | "ownership": "LEARNER_AUTHORED", | 실행 의미: manifest.json의 다음 검증 또는 설명 단계를 구성한다. |
| 36 | "starterAsset": "starter/src/main/java/com/example/financialcore/securities/CashWallet.java", | 실행 의미: manifest.json의 다음 검증 또는 설명 단계를 구성한다. |
| 37 | "starterSha256": "b88925eec28e4c4afb8a9438f490ddb99670c69e33b70b746ee8e1cd6ffcdd2d", | 실행 의미: starter 원시 bytes의 SHA-256을 manifest에 결박한다. |
| 38 | "starterCanonicalTextSha256": "b88925eec28e4c4afb8a9438f490ddb99670c69e33b70b746ee8e1cd6ffcdd2d", | 실행 의미: 현재 bytes를 64자리 digest로 evidence에 결박한다. |
| 39 | "solutionAsset": "solution/src/main/java/com/example/financialcore/securities/CashWallet.java", | 실행 의미: manifest.json의 다음 검증 또는 설명 단계를 구성한다. |
| 40 | "solutionSha256": "cdf78c1f20d8cdbb6304d89c0d4298e65de7d4eb64b39812c37fda28f26fb411", | 실행 의미: solution 원시 bytes의 SHA-256을 manifest에 결박한다. |
| 41 | "solutionCanonicalTextSha256": "cdf78c1f20d8cdbb6304d89c0d4298e65de7d4eb64b39812c37fda28f26fb411" | 실행 의미: 현재 bytes를 64자리 digest로 evidence에 결박한다. |
| 42 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 43 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
STEP 07 / 13
기존 수준의 한 줄 읽기·문법 해부
쉬운 설명 다음에 문법과 실행 순서를 정밀하게 읽습니다.
한 줄로 읽기SECURITIES manifest — 현금 available+reserved 불변식는 선택 트랙 selector·redMarker·starter/solution hash와 0/10_000 설명 계약을 고정한다.
문법 해부
- .json 문법에서 선언·조건·pipeline·block 경계를 먼저 나눈다.
- manifest의 finalState와 packaged progressive test의 1_000→700/300 oracle을 서로 다른 계약으로 읽는다.
- phase state·native exit·JUnit XML hash·보존된 XML bytes·사람 판정·USER_ATTESTED external status를 서로 대체하지 않는다.
실행 순서
- 기본 트랙은 SECURITIES(증권)이며, 명시적 CARD 선택은 기본값을 덮어쓴다. 실제 실행 전 최종 선택 한 개를 selected-track.csv·근거·state에 같은 값으로 기록하고 서로 다른 reference/learner root를 확인한다.
- Prepare→VerifyStarter→RecordRed→VerifySolution→RecordGreen→Cumulative→Review 순서를 지킨다.
- test를 소유한 세 phase에서만 native exit와 exact JUnit XML 수치를 판정한다.
- 다음 cleanTest 전에 XML bytes를 고유 경로에 보존하고 runtime history hash와 다시 묶는다. Review·Q41·sealed official evidence는 각자의 별도 owner와 검증 수준으로 남긴다.
W25 조각별 정밀 해설
F03-C01 · 원문 1–12줄
- 문법 해부
- .json 문법으로 1–12줄의 선언·조건·phase·assert block을 나눈다.
- 실제 값 추적
- SECURITIES, progressive_contract, W25_SECURITIES_RED_EXPECTED를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- 기본 SECURITIES 또는 명시적으로 덮어쓴 CARD 중 최종 선택 한 개의 selected-track evidence와 runtime 결과에서 expected와 actual이 일치하고 owner evidence가 같은 run/hash 및 보존 XML에 연결되는 경우다. 기본/덮어쓰기 표시만 있고 실행 evidence가 없으면 NOT_RUN이다.
- 틀린 예·반례
- manifest 문자열은 실행 결과가 아니다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- phase 이름·manifest finalState·history hash·exit0 하나를 W25 증거 전체와 같다고 보지 않는다.
- 하지 않는 일
- manifest 문자열은 실행 결과가 아니다; packaged test는 1_000→700/300만 assert한다; finalState 10_000은 별도 evidence가 필요하다; reference와 learner root는 서로 달라야 한다; 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다; 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
- 다음 연결
- 다음 조각 또는 F03 evidence 판정으로 상태를 넘긴다.
F03-C02 · 원문 13–24줄
- 문법 해부
- .json 문법으로 13–24줄의 선언·조건·phase·assert block을 나눈다.
- 실제 값 추적
- SECURITIES, progressive_contract, W25_SECURITIES_RED_EXPECTED를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- 기본 SECURITIES 또는 명시적으로 덮어쓴 CARD 중 최종 선택 한 개의 selected-track evidence와 runtime 결과에서 expected와 actual이 일치하고 owner evidence가 같은 run/hash 및 보존 XML에 연결되는 경우다. 기본/덮어쓰기 표시만 있고 실행 evidence가 없으면 NOT_RUN이다.
- 틀린 예·반례
- manifest 문자열은 실행 결과가 아니다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- phase 이름·manifest finalState·history hash·exit0 하나를 W25 증거 전체와 같다고 보지 않는다.
- 하지 않는 일
- manifest 문자열은 실행 결과가 아니다; packaged test는 1_000→700/300만 assert한다; finalState 10_000은 별도 evidence가 필요하다; reference와 learner root는 서로 달라야 한다; 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다; 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
- 다음 연결
- 다음 조각 또는 F03 evidence 판정으로 상태를 넘긴다.
F03-C03 · 원문 25–36줄
- 문법 해부
- .json 문법으로 25–36줄의 선언·조건·phase·assert block을 나눈다.
- 실제 값 추적
- SECURITIES, progressive_contract, W25_SECURITIES_RED_EXPECTED를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- 기본 SECURITIES 또는 명시적으로 덮어쓴 CARD 중 최종 선택 한 개의 selected-track evidence와 runtime 결과에서 expected와 actual이 일치하고 owner evidence가 같은 run/hash 및 보존 XML에 연결되는 경우다. 기본/덮어쓰기 표시만 있고 실행 evidence가 없으면 NOT_RUN이다.
- 틀린 예·반례
- manifest 문자열은 실행 결과가 아니다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- phase 이름·manifest finalState·history hash·exit0 하나를 W25 증거 전체와 같다고 보지 않는다.
- 하지 않는 일
- manifest 문자열은 실행 결과가 아니다; packaged test는 1_000→700/300만 assert한다; finalState 10_000은 별도 evidence가 필요하다; reference와 learner root는 서로 달라야 한다; 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다; 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
- 다음 연결
- 다음 조각 또는 F03 evidence 판정으로 상태를 넘긴다.
F03-C04 · 원문 37–43줄
- 문법 해부
- .json 문법으로 37–43줄의 선언·조건·phase·assert block을 나눈다.
- 실제 값 추적
- SECURITIES, progressive_contract, W25_SECURITIES_RED_EXPECTED를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- 기본 SECURITIES 또는 명시적으로 덮어쓴 CARD 중 최종 선택 한 개의 selected-track evidence와 runtime 결과에서 expected와 actual이 일치하고 owner evidence가 같은 run/hash 및 보존 XML에 연결되는 경우다. 기본/덮어쓰기 표시만 있고 실행 evidence가 없으면 NOT_RUN이다.
- 틀린 예·반례
- manifest 문자열은 실행 결과가 아니다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- phase 이름·manifest finalState·history hash·exit0 하나를 W25 증거 전체와 같다고 보지 않는다.
- 하지 않는 일
- manifest 문자열은 실행 결과가 아니다; packaged test는 1_000→700/300만 assert한다; finalState 10_000은 별도 evidence가 필요하다; reference와 learner root는 서로 달라야 한다; 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다; 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
- 다음 연결
- 다음 조각 또는 F03 evidence 판정으로 상태를 넘긴다.
실행 순서 — SECURITIES manifest — 현금 available+reserved 불변식
-
progressive_contract가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 선택 트랙 selector·redMarker·starter/solution hash와 0/10_000 설명 계약을 고정한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘packaged test는 1_000→700/300만 assert한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 progressive_contract와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 08 / 13
실제 값 따라가기
같은 입력값이 어느 줄을 지나 어떤 결과가 되는지 추적합니다.
| 순서 | 들어온 값 | 코드가 하는 일 | 나온 값·상태 | 경계 |
|---|---|---|---|---|
| 입력 | SECURITIES | source 계약에 대입 | F03 실행/설명 시작 상태 | manifest 문자열은 실행 결과가 아니다 |
| 검증 | progressive_contract | expected와 actual 또는 형식 대조 | 통과 또는 첫 mismatch | packaged test는 1_000→700/300만 assert한다 |
| 증거 | LEARNER_AUTHORED | marker·hash·row를 같은 run에 연결 | 범위가 적힌 evidence 후보 | 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다 |
실제 값 — SECURITIES manifest — 현금 available+reserved 불변식
-
W25_SECURITIES_RED_EXPECTED가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 선택 트랙 selector·redMarker·starter/solution hash와 0/10_000 설명 계약을 고정한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘finalState 10_000은 별도 evidence가 필요하다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 W25_SECURITIES_RED_EXPECTED와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 09 / 13
Gradle·JUnit XML·PowerShell·SQL 내부에서 벌어지는 일
세 test phase, XML bytes archive, Review, 별도 Q41, USER_ATTESTED sealed 결과의 owner와 증명 범위를 구분합니다.
manifest.json bytes와 track·phase·hash 계약을 읽는다.
SECURITIES 기본 선택과 파일 존재·phase 이름만으로 runtime Green을 주장할 수 없다. 실제 selected-track evidence와 실행 결과는 별도다.RecordRed·RecordGreen·Cumulative에서만 native exit와 exact JUnit XML을 만든다.
manifest 문자열은 실행 결과가 아니다XML bytes를 고유 파일로 보존하고 history hash와 묶은 뒤, Review는 기존 CumulativeGreen만 인용한다. Q41은 별도 PostgreSQL evidence, sealed official status는 user-attested evidence로 남긴다.
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다첫 실패 경계 — SECURITIES manifest — 현금 available+reserved 불변식
-
available=0,reserved=10_000가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 선택 트랙 selector·redMarker·starter/solution hash와 0/10_000 설명 계약을 고정한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘reference와 learner root는 서로 달라야 한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 available=0,reserved=10_000와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 10 / 13
흔한 착각과 틀린 예
그럴듯하지만 틀린 해석을 반례로 고칩니다.
❌ Prepare·VerifyStarter·VerifySolution·Review도 Gradle을 실행해 Green을 만든다.
왜 틀리나 runtime에서 test 실행을 소유하는 phase는 RecordRed·RecordGreen·Cumulative뿐이다.
바르게 읽기 각 phase history의 execution 유무와 mode를 직접 확인한다.
반례 VerifySolution은 solution hash만 검증하므로 새 JUnit XML이 없어야 정상이다.
❌ 기본 트랙이 SECURITIES이므로 CARD도 함께 실행해도 되고, 기본 배지만으로 runtime 선택·실행 증거가 완성된다.
왜 틀리나 W25 계약은 실제 사용자 근거가 있는 선택 트랙 하나와 반대 트랙 leak 부재를 요구한다.
바르게 읽기 기본 선택은 SECURITIES(증권)이며 명시적 CARD 선택은 덮어쓰기다. 실행 전 최종 선택 한 개를 selected-track.csv·근거·state에 같은 값으로 고정한다.
반례 SECURITIES 기본 배지만 보고 test 실행을 주장하거나 두 트랙 test가 함께 보이면 선택 경계를 위반한다.
❌ progressive_contract Green이면 manifest의 finalState 10_000도 증명된다.
왜 틀리나 packaged test는 1_000에서 300을 처리한 700/300만 assert한다.
바르게 읽기 10_000 finalState는 별도 learner test 또는 사람이 결박한 evidence로 증명한다.
반례 runtime은 domainContract.finalState 문자열을 parse하거나 assert하지 않는다.
❌ history에 XML SHA가 있으니 Red·Green·Cumulative XML 원본이 모두 보존됐다.
왜 틀리나 다음 cleanTest가 build/test-results의 이전 XML을 덮어쓰며 state는 bytes를 복사하지 않는다.
바르게 읽기 각 phase 직후 고유 evidence 경로로 원자 복사하고 hash를 history와 대조한다.
반례 RecordGreen 뒤에는 Red XML 경로가 사라질 수 있다.
❌ Review가 새 test를 실행해 CumulativeGreen을 다시 만들고 Q41·sealed official 결과까지 자동 확인한다.
왜 틀리나 Review는 기존 CumulativeGreen을 전제로 review entry와 leak check만 기록한다. Q41은 별도 PostgreSQL 과제이고 sealed official status는 user-attested다.
바르게 읽기 Review에서는 reviewedPhase와 history 증가만 보고, Q41 native evidence와 USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED sealed evidence를 별도로 판정한다.
반례 Review 뒤 phase는 여전히 CumulativeGreen이고 새 execution/XML·Q41 transcript·official login verification이 생기지 않는다.
STEP 11 / 13
이 코드가 보장하지 않는 것
선택 미결정·10_000 finalState·XML 보존·Review/Q41/sealed official truth처럼 이 코드가 책임지지 않는 일을 분리합니다.
manifest 문자열은 실행 결과가 아니다
이 책임을 맡는 곳: runtime Gatepackaged test는 1_000→700/300만 assert한다
이 책임을 맡는 곳: external/human reviewfinalState 10_000은 별도 evidence가 필요하다
이 책임을 맡는 곳: release manifestreference와 learner root는 서로 달라야 한다
이 책임을 맡는 곳: 운영 환경증명하지 않는 범위 — SECURITIES manifest — 현금 available+reserved 불변식
-
LEARNER_AUTHORED가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 선택 트랙 selector·redMarker·starter/solution hash와 0/10_000 설명 계약을 고정한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 LEARNER_AUTHORED와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 12 / 13
직접 다시 써보기
뜻 → 조각 → 전체 코드 순서로 다시 씁니다.
1단계 · 뜻부터 복원
- 선택 트랙 selector·redMarker·starter/solution hash와 0/10_000 설명 계약을 고정한다.
- 핵심 값은 SECURITIES, progressive_contract, W25_SECURITIES_RED_EXPECTED, available=0,reserved=10_000, LEARNER_AUTHORED다.
2단계 · 코드 조각 재조립
- 1. 앞에서 연 block 또는 호출 범위를 닫는다
- 2. manifest 형식 버전을 2로 고정한다
- 3. 이 계약이 W25에만 적용됨을 숫자로 고정한다
- 4. 이 manifest의 SECURITIES 또는 CARD 분기 identity를 고정할 뿐 실제 사용자 선택을 대신하지 않는다
- 5. manifest.json의 다음 검증 또는 설명 단계를 구성한다
- 6. manifest.json의 다음 검증 또는 설명 단계를 구성한다
- 7. manifest.json의 다음 검증 또는 설명 단계를 구성한다
- 8. manifest.json의 다음 검증 또는 설명 단계를 구성한다
3단계 · 파일 전체 다시 쓰기
track_learning_stages/securities/w25/manifest.json을 새 파일에 다시 쓰고 expected·actual·실패·cleanup·비범위를 주석으로 표시한다.
자가 점검
- 비어 있지 않은 모든 source 줄을 한 번씩 읽었나?
- 기본 트랙을 SECURITIES(증권) 하나로 두고 기본 선택·selected-track evidence·runtime Green을 서로 분리했나?
- Review·Q41·USER_ATTESTED sealed 상태를 자동 성공으로 꾸미지 않았나?
- XML bytes archive와 첫 실패·cleanup 책임을 설명할 수 있나?
STEP 13 / 13
전체 원본 source
감사로 고정한 전체 source를 가감 없이 확인합니다.
원문 정본 전체 source 확인하기
{
"schemaVersion": 2,
"week": 25,
"track": "SECURITIES",
"title": "현금 가용액·예약액 불변식",
"claim": "reserve 뒤 available+reserved 보존",
"textEncoding": "UTF-8",
"newlinePolicy": "LF_CANONICAL_CRLF_EQUIVALENT",
"domainContract": {
"invariant": "예약 전후 availableCash+reservedCash 합계가 보존되고 두 값은 음수가 아니다.",
"failureMode": "가용액 차감 누락으로 같은 현금을 중복 예약한다.",
"implementationTarget": "src/main/java/com/example/financialcore/securities/CashWallet.java :: 현금 가용액·예약액 불변식 :: reserve 뒤 available+reserved 보존",
"finalState": "available=0, reserved=10_000",
"recoveryFocus": "예약 전후 두 잔액과 합계를 먼저 비교한다.",
"interviewDefense": "현금 예약은 총액 보존과 음수 방지를 함께 증명해야 한다."
},
"selector": "com.example.financialcore.securities.W25CashWalletProgressiveTest",
"testMethod": "progressive_contract",
"redMarker": "W25_SECURITIES_RED_EXPECTED",
"predecessor": null,
"providedFiles": [],
"testFiles": [
{
"learnerPath": "src/test/java/com/example/financialcore/securities/W25CashWalletProgressiveTest.java",
"asset": "tests/src/test/java/com/example/financialcore/securities/W25CashWalletProgressiveTest.java",
"introducedAt": 25,
"ownership": "PROVIDED_FIXTURE_VERIFIED",
"sha256": "f45516879819dc698533b48c434ee2c374a03d150bdd834fe39501db65532312",
"canonicalTextSha256": "f45516879819dc698533b48c434ee2c374a03d150bdd834fe39501db65532312"
}
],
"authoredTarget": {
"learnerPath": "src/main/java/com/example/financialcore/securities/CashWallet.java",
"introducedAt": 25,
"ownership": "LEARNER_AUTHORED",
"starterAsset": "starter/src/main/java/com/example/financialcore/securities/CashWallet.java",
"starterSha256": "b88925eec28e4c4afb8a9438f490ddb99670c69e33b70b746ee8e1cd6ffcdd2d",
"starterCanonicalTextSha256": "b88925eec28e4c4afb8a9438f490ddb99670c69e33b70b746ee8e1cd6ffcdd2d",
"solutionAsset": "solution/src/main/java/com/example/financialcore/securities/CashWallet.java",
"solutionSha256": "cdf78c1f20d8cdbb6304d89c0d4298e65de7d4eb64b39812c37fda28f26fb411",
"solutionCanonicalTextSha256": "cdf78c1f20d8cdbb6304d89c0d4298e65de7d4eb64b39812c37fda28f26fb411"
}
}
04CARD manifest — 한도 available+used 불변식
track_learning_stages/card/w25/manifest.json
패키지 정본 보조 계약 · exact W25 manifest bytes · 정본 · W25-F0443줄 연결43줄 번역4 chunks
CARD manifest — 한도 available+used 불변식
track_learning_stages/card/w25/manifest.json
패키지 정본 보조 계약 · exact W25 manifest bytes · 정본 · W25-F04STEP 01 / 13
오늘 이 코드에서 해결할 문제
무엇을 이해해야 하는지 질문부터 잡습니다.
선택 트랙 selector·redMarker·starter/solution hash와 0/10_000 설명 계약을 고정한다.
- CARD은 어느 source와 실제 결과에서 확인해야 할까?
- 첫 실패를 만드는 조건과 fail-closed 지점은 어디일까?
- 왜 ‘manifest 문자열은 실행 결과가 아니다’를 별도 경계로 남겨야 할까?
CARDprogressive_contractW25_CARD_RED_EXPECTEDavailable=0,used=10_000LEARNER_AUTHORED왜 필요한가 — CARD manifest — 한도 available+used 불변식
-
CARD가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 선택 트랙 selector·redMarker·starter/solution hash와 0/10_000 설명 계약을 고정한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘manifest 문자열은 실행 결과가 아니다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 CARD와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 02 / 13
아주 짧게: 이 코드는 왜 필요할까?
웹소설 대신 이 코드가 필요한 이유만 두 문단으로 쉽게 봅니다.
사용자의 기본 선택에 따라 이 HTML은 SECURITIES(증권)을 주 트랙으로 읽는다. CARD는 비교용이며 명시적으로 고르면 기본값을 덮어쓸 수 있다. 실제 실행은 최종 선택 한 개를 selected-track.csv·근거·state에 같은 값으로 기록하고 reference와 learner 폴더를 분리한 뒤에만 시작한다. 이 HTML 자체는 Gradle/JUnit을 실행하지 않아 NOT_RUN 상태다.
한 통장만 골라 빨강에서 초록까지 증명하는 일주일
이 파일은 선택 트랙 selector·redMarker·starter/solution hash와 0/10_000 설명 계약을 고정한다. 눈으로 읽을 때는 각 줄을 검수표 한 칸처럼 보고, 입력과 다음 상태를 놓치지 않는다.
마지막 도장은 hash 확인, 세 test phase의 실제 JUnit 실행, XML bytes archive, 사람 review를 서로 구분한 뒤에만 찍는다. Review는 새 test가 아니며 Q41은 stage runtime 밖의 별도 NOT_RUN 과제, sealed official status는 USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED다. 특히 manifest 문자열은 실행 결과가 아니다
딱 여기까지만 비유와 SECURITIES 기본 배지는 실제 selected-track 근거, Gradle/JUnit 실행, XML bytes 보존, 사람 review, Q41 실행, sealed official 확인을 대신하지 않는다.
STEP 03 / 13
초등학생도 이해하는 설명
생활 비유와 실제 코드의 경계를 함께 확인합니다.
값 1: CARD
이 파일에서 계속 확인할 고정 단서가 CARD다.
- 코드 연결
F04 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- manifest 문자열은 실행 결과가 아니다
값 2: progressive_contract
이 파일에서 계속 확인할 고정 단서가 progressive_contract다.
- 코드 연결
F04 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- packaged test는 1_000→300/700만 assert한다
값 3: W25_CARD_RED_EXPECTED
이 파일에서 계속 확인할 고정 단서가 W25_CARD_RED_EXPECTED다.
- 코드 연결
F04 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- finalState 10_000은 별도 evidence가 필요하다
값 4: available=0,used=10_000
이 파일에서 계속 확인할 고정 단서가 available=0,used=10_000다.
- 코드 연결
F04 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- reference와 learner root는 서로 달라야 한다
값 5: LEARNER_AUTHORED
이 파일에서 계속 확인할 고정 단서가 LEARNER_AUTHORED다.
- 코드 연결
F04 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
STEP 04 / 13
비유 ↔ 코드 전체 연결표
감사 규칙상 연결 대상인 원본 43줄을 빠짐없이 연결합니다.
| 줄 | 정확한 원본 줄 | STARRY 비유 | 실제 뜻·입력·결과·한계 |
|---|---|---|---|
| 1줄F04-L01 | { |
출고표 1번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 2줄F04-L02 | "schemaVersion": |
출고표 2번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 manifest 형식 버전을 2로 고정한다.
|
| 3줄F04-L03 | "week": |
출고표 3번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 이 계약이 W25에만 적용됨을 숫자로 고정한다.
|
| 4줄F04-L04 | "track": |
출고표 4번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 이 manifest의 SECURITIES 또는 CARD 분기 identity를 고정할 뿐 실제 사용자 선택을 대신하지 않는다.
|
| 5줄F04-L05 | "title": |
출고표 5번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 manifest.json의 다음 검증 또는 설명 단계를 구성한다.
|
| 6줄F04-L06 | "claim": |
출고표 6번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 manifest.json의 다음 검증 또는 설명 단계를 구성한다.
|
| 7줄F04-L07 | "textEncoding": |
출고표 7번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 manifest.json의 다음 검증 또는 설명 단계를 구성한다.
|
| 8줄F04-L08 | "newlinePolicy": |
출고표 8번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 manifest.json의 다음 검증 또는 설명 단계를 구성한다.
|
| 9줄F04-L09 | "domainContract": |
출고표 9번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 불변식·실패 모드·최종 상태처럼 도메인 설명을 한 묶음으로 연다.
|
| 10줄F04-L10 | "invariant": |
출고표 10번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 두 잔액의 합계 보존과 음수 금지라는 핵심 불변식을 설명한다.
|
| 11줄F04-L11 | "failureMode": |
출고표 11번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 차감 또는 증가 누락이 같은 돈·한도의 중복 사용으로 이어짐을 밝힌다.
|
| 12줄F04-L12 | "implementationTarget": |
출고표 12번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 manifest.json의 다음 검증 또는 설명 단계를 구성한다.
|
| 13줄F04-L13 | "finalState": |
출고표 13번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 PDF가 요구하는 10_000 시나리오를 설명용 계약에 고정하며 packaged 1_000→700/300 test의 자동 assertion과 분리한다.
|
| 14줄F04-L14 | "recoveryFocus": |
출고표 14번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 manifest.json의 다음 검증 또는 설명 단계를 구성한다.
|
| 15줄F04-L15 | "interviewDefense": |
출고표 15번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 manifest.json의 다음 검증 또는 설명 단계를 구성한다.
|
| 16줄F04-L16 | }, |
출고표 16번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 manifest.json의 다음 검증 또는 설명 단계를 구성한다.
|
| 17줄F04-L17 | "selector": |
출고표 17번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 선택 트랙의 정확한 JUnit suite 이름 하나를 지정한다.
|
| 18줄F04-L18 | "testMethod": |
출고표 18번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 progressive_contract 메서드 하나를 W25 proof 대상으로 지정한다.
|
| 19줄F04-L19 | "redMarker": |
출고표 19번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 의도한 Red 실패를 다른 실패와 구분할 marker를 고정한다.
|
| 20줄F04-L20 | "predecessor": |
출고표 20번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 manifest.json의 다음 검증 또는 설명 단계를 구성한다.
|
| 21줄F04-L21 | "providedFiles": |
출고표 21번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 manifest.json의 다음 검증 또는 설명 단계를 구성한다.
|
| 22줄F04-L22 | "testFiles": |
출고표 22번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 manifest.json의 다음 검증 또는 설명 단계를 구성한다.
|
| 23줄F04-L23 | { |
출고표 23번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 24줄F04-L24 | "learnerPath": |
출고표 24번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 manifest.json의 다음 검증 또는 설명 단계를 구성한다.
|
| 25줄F04-L25 | "asset": |
출고표 25번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 manifest.json의 다음 검증 또는 설명 단계를 구성한다.
|
| 26줄F04-L26 | "introducedAt": |
출고표 26번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 manifest.json의 다음 검증 또는 설명 단계를 구성한다.
|
| 27줄F04-L27 | "ownership": |
출고표 27번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 manifest.json의 다음 검증 또는 설명 단계를 구성한다.
|
| 28줄F04-L28 | "sha256": |
출고표 28번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 현재 bytes를 64자리 digest로 evidence에 결박한다.
|
| 29줄F04-L29 | "canonicalTextSha256": |
출고표 29번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 현재 bytes를 64자리 digest로 evidence에 결박한다.
|
| 30줄F04-L30 | } |
출고표 30번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 31줄F04-L31 | ], |
출고표 31번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 manifest.json의 다음 검증 또는 설명 단계를 구성한다.
|
| 32줄F04-L32 | "authoredTarget": |
출고표 32번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 학습자가 직접 소유하는 main Java 경로와 starter/solution hash를 묶는다.
|
| 33줄F04-L33 | "learnerPath": |
출고표 33번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 manifest.json의 다음 검증 또는 설명 단계를 구성한다.
|
| 34줄F04-L34 | "introducedAt": |
출고표 34번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 manifest.json의 다음 검증 또는 설명 단계를 구성한다.
|
| 35줄F04-L35 | "ownership": |
출고표 35번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 manifest.json의 다음 검증 또는 설명 단계를 구성한다.
|
| 36줄F04-L36 | "starterAsset": |
출고표 36번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 manifest.json의 다음 검증 또는 설명 단계를 구성한다.
|
| 37줄F04-L37 | "starterSha256": |
출고표 37번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 starter 원시 bytes의 SHA-256을 manifest에 결박한다.
|
| 38줄F04-L38 | "starterCanonicalTextSha256": |
출고표 38번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 현재 bytes를 64자리 digest로 evidence에 결박한다.
|
| 39줄F04-L39 | "solutionAsset": |
출고표 39번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 manifest.json의 다음 검증 또는 설명 단계를 구성한다.
|
| 40줄F04-L40 | "solutionSha256": |
출고표 40번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 solution 원시 bytes의 SHA-256을 manifest에 결박한다.
|
| 41줄F04-L41 | "solutionCanonicalTextSha256": |
출고표 41번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 현재 bytes를 64자리 digest로 evidence에 결박한다.
|
| 42줄F04-L42 | } |
출고표 42번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 43줄F04-L43 | } |
출고표 43번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
STEP 05 / 13
원본 코드 조각
원본을 4개 의미 조각으로 나누어 그대로 확인합니다.
파일을 한꺼번에 외우지 않고 실행 의미가 이어지는 작은 조각으로 봅니다. 아래 코드는 hash로 고정한 native 정본 source에서 그대로 잘랐습니다.
{
"schemaVersion": 2,
"week": 25,
"track": "CARD",
"title": "한도 가용액·사용액 불변식",
"claim": "hold 뒤 available+used 보존",
"textEncoding": "UTF-8",
"newlinePolicy": "LF_CANONICAL_CRLF_EQUIVALENT",
"domainContract": {
"invariant": "hold 전후 availableLimit+usedAmount가 creditLimit와 같고 음수가 아니다.",
"failureMode": "usedAmount 증가 누락으로 같은 한도를 반복 승인한다.",
"implementationTarget": "src/main/java/com/example/financialcore/card/CardAccount.java :: 한도 가용액·사용액 불변식 :: hold 뒤 available+used 보존",
"finalState": "available=0, used=10_000",
"recoveryFocus": "승인 전후 한도 두 값과 합계를 비교한다.",
"interviewDefense": "카드 한도 hold는 사용액 증가와 가용 한도 감소를 함께 증명한다."
},
"selector": "com.example.financialcore.card.W25CardLimitProgressiveTest",
"testMethod": "progressive_contract",
"redMarker": "W25_CARD_RED_EXPECTED",
"predecessor": null,
"providedFiles": [],
"testFiles": [
{
"learnerPath": "src/test/java/com/example/financialcore/card/W25CardLimitProgressiveTest.java",
"asset": "tests/src/test/java/com/example/financialcore/card/W25CardLimitProgressiveTest.java",
"introducedAt": 25,
"ownership": "PROVIDED_FIXTURE_VERIFIED",
"sha256": "9cdba356b51a1b7c78fad4b1da205f021b67f17705cae12a0382cd835dda6459",
"canonicalTextSha256": "9cdba356b51a1b7c78fad4b1da205f021b67f17705cae12a0382cd835dda6459"
}
],
"authoredTarget": {
"learnerPath": "src/main/java/com/example/financialcore/card/CardAccount.java",
"introducedAt": 25,
"ownership": "LEARNER_AUTHORED",
"starterAsset": "starter/src/main/java/com/example/financialcore/card/CardAccount.java",
"starterSha256": "cc62b9dd28d90f23ada49f810436ed04ce2d604e6b902d72183a7887bbc07ea2",
"starterCanonicalTextSha256": "cc62b9dd28d90f23ada49f810436ed04ce2d604e6b902d72183a7887bbc07ea2",
"solutionAsset": "solution/src/main/java/com/example/financialcore/card/CardAccount.java",
"solutionSha256": "3a142277feffdb89156bbce21dde495d299564a7c1c4a036f7d4505f96fea0e3",
"solutionCanonicalTextSha256": "3a142277feffdb89156bbce21dde495d299564a7c1c4a036f7d4505f96fea0e3"
}
}
STEP 06 / 13
코드 한 줄씩 한국어로 번역
비어 있지 않은 43줄을 모두 한국어로 옮깁니다.
비어 있지 않은 원본 줄은 하나도 생략하지 않습니다.
| 줄 | 원본 | 한국어 번역 |
|---|---|---|
| 1 | { | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 2 | "schemaVersion": 2, | 실행 의미: manifest 형식 버전을 2로 고정한다. |
| 3 | "week": 25, | 실행 의미: 이 계약이 W25에만 적용됨을 숫자로 고정한다. |
| 4 | "track": "CARD", | 실행 의미: 이 manifest의 SECURITIES 또는 CARD 분기 identity를 고정할 뿐 실제 사용자 선택을 대신하지 않는다. |
| 5 | "title": "한도 가용액·사용액 불변식", | 실행 의미: manifest.json의 다음 검증 또는 설명 단계를 구성한다. |
| 6 | "claim": "hold 뒤 available+used 보존", | 실행 의미: manifest.json의 다음 검증 또는 설명 단계를 구성한다. |
| 7 | "textEncoding": "UTF-8", | 실행 의미: manifest.json의 다음 검증 또는 설명 단계를 구성한다. |
| 8 | "newlinePolicy": "LF_CANONICAL_CRLF_EQUIVALENT", | 실행 의미: manifest.json의 다음 검증 또는 설명 단계를 구성한다. |
| 9 | "domainContract": { | 실행 의미: 불변식·실패 모드·최종 상태처럼 도메인 설명을 한 묶음으로 연다. |
| 10 | "invariant": "hold 전후 availableLimit+usedAmount가 creditLimit와 같고 음수가 아니다.", | 실행 의미: 두 잔액의 합계 보존과 음수 금지라는 핵심 불변식을 설명한다. |
| 11 | "failureMode": "usedAmount 증가 누락으로 같은 한도를 반복 승인한다.", | 실행 의미: 차감 또는 증가 누락이 같은 돈·한도의 중복 사용으로 이어짐을 밝힌다. |
| 12 | "implementationTarget": "src/main/java/com/example/financialcore/card/CardAccount.java :: 한도 가용액·사용액 불변식 :: hold 뒤 available+used 보존", | 실행 의미: manifest.json의 다음 검증 또는 설명 단계를 구성한다. |
| 13 | "finalState": "available=0, used=10_000", | 실행 의미: PDF가 요구하는 10_000 시나리오를 설명용 계약에 고정하며 packaged 1_000→700/300 test의 자동 assertion과 분리한다. |
| 14 | "recoveryFocus": "승인 전후 한도 두 값과 합계를 비교한다.", | 실행 의미: manifest.json의 다음 검증 또는 설명 단계를 구성한다. |
| 15 | "interviewDefense": "카드 한도 hold는 사용액 증가와 가용 한도 감소를 함께 증명한다." | 실행 의미: manifest.json의 다음 검증 또는 설명 단계를 구성한다. |
| 16 | }, | 실행 의미: manifest.json의 다음 검증 또는 설명 단계를 구성한다. |
| 17 | "selector": "com.example.financialcore.card.W25CardLimitProgressiveTest", | 실행 의미: 선택 트랙의 정확한 JUnit suite 이름 하나를 지정한다. |
| 18 | "testMethod": "progressive_contract", | 실행 의미: progressive_contract 메서드 하나를 W25 proof 대상으로 지정한다. |
| 19 | "redMarker": "W25_CARD_RED_EXPECTED", | 실행 의미: 의도한 Red 실패를 다른 실패와 구분할 marker를 고정한다. |
| 20 | "predecessor": null, | 실행 의미: manifest.json의 다음 검증 또는 설명 단계를 구성한다. |
| 21 | "providedFiles": [], | 실행 의미: manifest.json의 다음 검증 또는 설명 단계를 구성한다. |
| 22 | "testFiles": [ | 실행 의미: manifest.json의 다음 검증 또는 설명 단계를 구성한다. |
| 23 | { | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 24 | "learnerPath": "src/test/java/com/example/financialcore/card/W25CardLimitProgressiveTest.java", | 실행 의미: manifest.json의 다음 검증 또는 설명 단계를 구성한다. |
| 25 | "asset": "tests/src/test/java/com/example/financialcore/card/W25CardLimitProgressiveTest.java", | 실행 의미: manifest.json의 다음 검증 또는 설명 단계를 구성한다. |
| 26 | "introducedAt": 25, | 실행 의미: manifest.json의 다음 검증 또는 설명 단계를 구성한다. |
| 27 | "ownership": "PROVIDED_FIXTURE_VERIFIED", | 실행 의미: manifest.json의 다음 검증 또는 설명 단계를 구성한다. |
| 28 | "sha256": "9cdba356b51a1b7c78fad4b1da205f021b67f17705cae12a0382cd835dda6459", | 실행 의미: 현재 bytes를 64자리 digest로 evidence에 결박한다. |
| 29 | "canonicalTextSha256": "9cdba356b51a1b7c78fad4b1da205f021b67f17705cae12a0382cd835dda6459" | 실행 의미: 현재 bytes를 64자리 digest로 evidence에 결박한다. |
| 30 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 31 | ], | 실행 의미: manifest.json의 다음 검증 또는 설명 단계를 구성한다. |
| 32 | "authoredTarget": { | 실행 의미: 학습자가 직접 소유하는 main Java 경로와 starter/solution hash를 묶는다. |
| 33 | "learnerPath": "src/main/java/com/example/financialcore/card/CardAccount.java", | 실행 의미: manifest.json의 다음 검증 또는 설명 단계를 구성한다. |
| 34 | "introducedAt": 25, | 실행 의미: manifest.json의 다음 검증 또는 설명 단계를 구성한다. |
| 35 | "ownership": "LEARNER_AUTHORED", | 실행 의미: manifest.json의 다음 검증 또는 설명 단계를 구성한다. |
| 36 | "starterAsset": "starter/src/main/java/com/example/financialcore/card/CardAccount.java", | 실행 의미: manifest.json의 다음 검증 또는 설명 단계를 구성한다. |
| 37 | "starterSha256": "cc62b9dd28d90f23ada49f810436ed04ce2d604e6b902d72183a7887bbc07ea2", | 실행 의미: starter 원시 bytes의 SHA-256을 manifest에 결박한다. |
| 38 | "starterCanonicalTextSha256": "cc62b9dd28d90f23ada49f810436ed04ce2d604e6b902d72183a7887bbc07ea2", | 실행 의미: 현재 bytes를 64자리 digest로 evidence에 결박한다. |
| 39 | "solutionAsset": "solution/src/main/java/com/example/financialcore/card/CardAccount.java", | 실행 의미: manifest.json의 다음 검증 또는 설명 단계를 구성한다. |
| 40 | "solutionSha256": "3a142277feffdb89156bbce21dde495d299564a7c1c4a036f7d4505f96fea0e3", | 실행 의미: solution 원시 bytes의 SHA-256을 manifest에 결박한다. |
| 41 | "solutionCanonicalTextSha256": "3a142277feffdb89156bbce21dde495d299564a7c1c4a036f7d4505f96fea0e3" | 실행 의미: 현재 bytes를 64자리 digest로 evidence에 결박한다. |
| 42 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 43 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
STEP 07 / 13
기존 수준의 한 줄 읽기·문법 해부
쉬운 설명 다음에 문법과 실행 순서를 정밀하게 읽습니다.
한 줄로 읽기CARD manifest — 한도 available+used 불변식는 선택 트랙 selector·redMarker·starter/solution hash와 0/10_000 설명 계약을 고정한다.
문법 해부
- .json 문법에서 선언·조건·pipeline·block 경계를 먼저 나눈다.
- manifest의 finalState와 packaged progressive test의 1_000→700/300 oracle을 서로 다른 계약으로 읽는다.
- phase state·native exit·JUnit XML hash·보존된 XML bytes·사람 판정·USER_ATTESTED external status를 서로 대체하지 않는다.
실행 순서
- 기본 트랙은 SECURITIES(증권)이며, 명시적 CARD 선택은 기본값을 덮어쓴다. 실제 실행 전 최종 선택 한 개를 selected-track.csv·근거·state에 같은 값으로 기록하고 서로 다른 reference/learner root를 확인한다.
- Prepare→VerifyStarter→RecordRed→VerifySolution→RecordGreen→Cumulative→Review 순서를 지킨다.
- test를 소유한 세 phase에서만 native exit와 exact JUnit XML 수치를 판정한다.
- 다음 cleanTest 전에 XML bytes를 고유 경로에 보존하고 runtime history hash와 다시 묶는다. Review·Q41·sealed official evidence는 각자의 별도 owner와 검증 수준으로 남긴다.
W25 조각별 정밀 해설
F04-C01 · 원문 1–12줄
- 문법 해부
- .json 문법으로 1–12줄의 선언·조건·phase·assert block을 나눈다.
- 실제 값 추적
- CARD, progressive_contract, W25_CARD_RED_EXPECTED를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- 기본 SECURITIES 또는 명시적으로 덮어쓴 CARD 중 최종 선택 한 개의 selected-track evidence와 runtime 결과에서 expected와 actual이 일치하고 owner evidence가 같은 run/hash 및 보존 XML에 연결되는 경우다. 기본/덮어쓰기 표시만 있고 실행 evidence가 없으면 NOT_RUN이다.
- 틀린 예·반례
- manifest 문자열은 실행 결과가 아니다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- phase 이름·manifest finalState·history hash·exit0 하나를 W25 증거 전체와 같다고 보지 않는다.
- 하지 않는 일
- manifest 문자열은 실행 결과가 아니다; packaged test는 1_000→300/700만 assert한다; finalState 10_000은 별도 evidence가 필요하다; reference와 learner root는 서로 달라야 한다; 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다; 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
- 다음 연결
- 다음 조각 또는 F04 evidence 판정으로 상태를 넘긴다.
F04-C02 · 원문 13–24줄
- 문법 해부
- .json 문법으로 13–24줄의 선언·조건·phase·assert block을 나눈다.
- 실제 값 추적
- CARD, progressive_contract, W25_CARD_RED_EXPECTED를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- 기본 SECURITIES 또는 명시적으로 덮어쓴 CARD 중 최종 선택 한 개의 selected-track evidence와 runtime 결과에서 expected와 actual이 일치하고 owner evidence가 같은 run/hash 및 보존 XML에 연결되는 경우다. 기본/덮어쓰기 표시만 있고 실행 evidence가 없으면 NOT_RUN이다.
- 틀린 예·반례
- manifest 문자열은 실행 결과가 아니다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- phase 이름·manifest finalState·history hash·exit0 하나를 W25 증거 전체와 같다고 보지 않는다.
- 하지 않는 일
- manifest 문자열은 실행 결과가 아니다; packaged test는 1_000→300/700만 assert한다; finalState 10_000은 별도 evidence가 필요하다; reference와 learner root는 서로 달라야 한다; 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다; 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
- 다음 연결
- 다음 조각 또는 F04 evidence 판정으로 상태를 넘긴다.
F04-C03 · 원문 25–36줄
- 문법 해부
- .json 문법으로 25–36줄의 선언·조건·phase·assert block을 나눈다.
- 실제 값 추적
- CARD, progressive_contract, W25_CARD_RED_EXPECTED를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- 기본 SECURITIES 또는 명시적으로 덮어쓴 CARD 중 최종 선택 한 개의 selected-track evidence와 runtime 결과에서 expected와 actual이 일치하고 owner evidence가 같은 run/hash 및 보존 XML에 연결되는 경우다. 기본/덮어쓰기 표시만 있고 실행 evidence가 없으면 NOT_RUN이다.
- 틀린 예·반례
- manifest 문자열은 실행 결과가 아니다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- phase 이름·manifest finalState·history hash·exit0 하나를 W25 증거 전체와 같다고 보지 않는다.
- 하지 않는 일
- manifest 문자열은 실행 결과가 아니다; packaged test는 1_000→300/700만 assert한다; finalState 10_000은 별도 evidence가 필요하다; reference와 learner root는 서로 달라야 한다; 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다; 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
- 다음 연결
- 다음 조각 또는 F04 evidence 판정으로 상태를 넘긴다.
F04-C04 · 원문 37–43줄
- 문법 해부
- .json 문법으로 37–43줄의 선언·조건·phase·assert block을 나눈다.
- 실제 값 추적
- CARD, progressive_contract, W25_CARD_RED_EXPECTED를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- 기본 SECURITIES 또는 명시적으로 덮어쓴 CARD 중 최종 선택 한 개의 selected-track evidence와 runtime 결과에서 expected와 actual이 일치하고 owner evidence가 같은 run/hash 및 보존 XML에 연결되는 경우다. 기본/덮어쓰기 표시만 있고 실행 evidence가 없으면 NOT_RUN이다.
- 틀린 예·반례
- manifest 문자열은 실행 결과가 아니다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- phase 이름·manifest finalState·history hash·exit0 하나를 W25 증거 전체와 같다고 보지 않는다.
- 하지 않는 일
- manifest 문자열은 실행 결과가 아니다; packaged test는 1_000→300/700만 assert한다; finalState 10_000은 별도 evidence가 필요하다; reference와 learner root는 서로 달라야 한다; 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다; 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
- 다음 연결
- 다음 조각 또는 F04 evidence 판정으로 상태를 넘긴다.
실행 순서 — CARD manifest — 한도 available+used 불변식
-
progressive_contract가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 선택 트랙 selector·redMarker·starter/solution hash와 0/10_000 설명 계약을 고정한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘packaged test는 1_000→300/700만 assert한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 progressive_contract와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 08 / 13
실제 값 따라가기
같은 입력값이 어느 줄을 지나 어떤 결과가 되는지 추적합니다.
| 순서 | 들어온 값 | 코드가 하는 일 | 나온 값·상태 | 경계 |
|---|---|---|---|---|
| 입력 | CARD | source 계약에 대입 | F04 실행/설명 시작 상태 | manifest 문자열은 실행 결과가 아니다 |
| 검증 | progressive_contract | expected와 actual 또는 형식 대조 | 통과 또는 첫 mismatch | packaged test는 1_000→300/700만 assert한다 |
| 증거 | LEARNER_AUTHORED | marker·hash·row를 같은 run에 연결 | 범위가 적힌 evidence 후보 | 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다 |
실제 값 — CARD manifest — 한도 available+used 불변식
-
W25_CARD_RED_EXPECTED가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 선택 트랙 selector·redMarker·starter/solution hash와 0/10_000 설명 계약을 고정한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘finalState 10_000은 별도 evidence가 필요하다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 W25_CARD_RED_EXPECTED와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 09 / 13
Gradle·JUnit XML·PowerShell·SQL 내부에서 벌어지는 일
세 test phase, XML bytes archive, Review, 별도 Q41, USER_ATTESTED sealed 결과의 owner와 증명 범위를 구분합니다.
manifest.json bytes와 track·phase·hash 계약을 읽는다.
SECURITIES 기본 선택과 파일 존재·phase 이름만으로 runtime Green을 주장할 수 없다. 실제 selected-track evidence와 실행 결과는 별도다.RecordRed·RecordGreen·Cumulative에서만 native exit와 exact JUnit XML을 만든다.
manifest 문자열은 실행 결과가 아니다XML bytes를 고유 파일로 보존하고 history hash와 묶은 뒤, Review는 기존 CumulativeGreen만 인용한다. Q41은 별도 PostgreSQL evidence, sealed official status는 user-attested evidence로 남긴다.
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다첫 실패 경계 — CARD manifest — 한도 available+used 불변식
-
available=0,used=10_000가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 선택 트랙 selector·redMarker·starter/solution hash와 0/10_000 설명 계약을 고정한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘reference와 learner root는 서로 달라야 한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 available=0,used=10_000와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 10 / 13
흔한 착각과 틀린 예
그럴듯하지만 틀린 해석을 반례로 고칩니다.
❌ Prepare·VerifyStarter·VerifySolution·Review도 Gradle을 실행해 Green을 만든다.
왜 틀리나 runtime에서 test 실행을 소유하는 phase는 RecordRed·RecordGreen·Cumulative뿐이다.
바르게 읽기 각 phase history의 execution 유무와 mode를 직접 확인한다.
반례 VerifySolution은 solution hash만 검증하므로 새 JUnit XML이 없어야 정상이다.
❌ 기본 트랙이 SECURITIES이므로 CARD도 함께 실행해도 되고, 기본 배지만으로 runtime 선택·실행 증거가 완성된다.
왜 틀리나 W25 계약은 실제 사용자 근거가 있는 선택 트랙 하나와 반대 트랙 leak 부재를 요구한다.
바르게 읽기 기본 선택은 SECURITIES(증권)이며 명시적 CARD 선택은 덮어쓰기다. 실행 전 최종 선택 한 개를 selected-track.csv·근거·state에 같은 값으로 고정한다.
반례 SECURITIES 기본 배지만 보고 test 실행을 주장하거나 두 트랙 test가 함께 보이면 선택 경계를 위반한다.
❌ progressive_contract Green이면 manifest의 finalState 10_000도 증명된다.
왜 틀리나 packaged test는 1_000에서 300을 처리한 700/300만 assert한다.
바르게 읽기 10_000 finalState는 별도 learner test 또는 사람이 결박한 evidence로 증명한다.
반례 runtime은 domainContract.finalState 문자열을 parse하거나 assert하지 않는다.
❌ history에 XML SHA가 있으니 Red·Green·Cumulative XML 원본이 모두 보존됐다.
왜 틀리나 다음 cleanTest가 build/test-results의 이전 XML을 덮어쓰며 state는 bytes를 복사하지 않는다.
바르게 읽기 각 phase 직후 고유 evidence 경로로 원자 복사하고 hash를 history와 대조한다.
반례 RecordGreen 뒤에는 Red XML 경로가 사라질 수 있다.
❌ Review가 새 test를 실행해 CumulativeGreen을 다시 만들고 Q41·sealed official 결과까지 자동 확인한다.
왜 틀리나 Review는 기존 CumulativeGreen을 전제로 review entry와 leak check만 기록한다. Q41은 별도 PostgreSQL 과제이고 sealed official status는 user-attested다.
바르게 읽기 Review에서는 reviewedPhase와 history 증가만 보고, Q41 native evidence와 USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED sealed evidence를 별도로 판정한다.
반례 Review 뒤 phase는 여전히 CumulativeGreen이고 새 execution/XML·Q41 transcript·official login verification이 생기지 않는다.
STEP 11 / 13
이 코드가 보장하지 않는 것
선택 미결정·10_000 finalState·XML 보존·Review/Q41/sealed official truth처럼 이 코드가 책임지지 않는 일을 분리합니다.
manifest 문자열은 실행 결과가 아니다
이 책임을 맡는 곳: runtime Gatepackaged test는 1_000→300/700만 assert한다
이 책임을 맡는 곳: external/human reviewfinalState 10_000은 별도 evidence가 필요하다
이 책임을 맡는 곳: release manifestreference와 learner root는 서로 달라야 한다
이 책임을 맡는 곳: 운영 환경증명하지 않는 범위 — CARD manifest — 한도 available+used 불변식
-
LEARNER_AUTHORED가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 선택 트랙 selector·redMarker·starter/solution hash와 0/10_000 설명 계약을 고정한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 LEARNER_AUTHORED와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 12 / 13
직접 다시 써보기
뜻 → 조각 → 전체 코드 순서로 다시 씁니다.
1단계 · 뜻부터 복원
- 선택 트랙 selector·redMarker·starter/solution hash와 0/10_000 설명 계약을 고정한다.
- 핵심 값은 CARD, progressive_contract, W25_CARD_RED_EXPECTED, available=0,used=10_000, LEARNER_AUTHORED다.
2단계 · 코드 조각 재조립
- 1. 앞에서 연 block 또는 호출 범위를 닫는다
- 2. manifest 형식 버전을 2로 고정한다
- 3. 이 계약이 W25에만 적용됨을 숫자로 고정한다
- 4. 이 manifest의 SECURITIES 또는 CARD 분기 identity를 고정할 뿐 실제 사용자 선택을 대신하지 않는다
- 5. manifest.json의 다음 검증 또는 설명 단계를 구성한다
- 6. manifest.json의 다음 검증 또는 설명 단계를 구성한다
- 7. manifest.json의 다음 검증 또는 설명 단계를 구성한다
- 8. manifest.json의 다음 검증 또는 설명 단계를 구성한다
3단계 · 파일 전체 다시 쓰기
track_learning_stages/card/w25/manifest.json을 새 파일에 다시 쓰고 expected·actual·실패·cleanup·비범위를 주석으로 표시한다.
자가 점검
- 비어 있지 않은 모든 source 줄을 한 번씩 읽었나?
- 기본 트랙을 SECURITIES(증권) 하나로 두고 기본 선택·selected-track evidence·runtime Green을 서로 분리했나?
- Review·Q41·USER_ATTESTED sealed 상태를 자동 성공으로 꾸미지 않았나?
- XML bytes archive와 첫 실패·cleanup 책임을 설명할 수 있나?
STEP 13 / 13
전체 원본 source
감사로 고정한 전체 source를 가감 없이 확인합니다.
원문 정본 전체 source 확인하기
{
"schemaVersion": 2,
"week": 25,
"track": "CARD",
"title": "한도 가용액·사용액 불변식",
"claim": "hold 뒤 available+used 보존",
"textEncoding": "UTF-8",
"newlinePolicy": "LF_CANONICAL_CRLF_EQUIVALENT",
"domainContract": {
"invariant": "hold 전후 availableLimit+usedAmount가 creditLimit와 같고 음수가 아니다.",
"failureMode": "usedAmount 증가 누락으로 같은 한도를 반복 승인한다.",
"implementationTarget": "src/main/java/com/example/financialcore/card/CardAccount.java :: 한도 가용액·사용액 불변식 :: hold 뒤 available+used 보존",
"finalState": "available=0, used=10_000",
"recoveryFocus": "승인 전후 한도 두 값과 합계를 비교한다.",
"interviewDefense": "카드 한도 hold는 사용액 증가와 가용 한도 감소를 함께 증명한다."
},
"selector": "com.example.financialcore.card.W25CardLimitProgressiveTest",
"testMethod": "progressive_contract",
"redMarker": "W25_CARD_RED_EXPECTED",
"predecessor": null,
"providedFiles": [],
"testFiles": [
{
"learnerPath": "src/test/java/com/example/financialcore/card/W25CardLimitProgressiveTest.java",
"asset": "tests/src/test/java/com/example/financialcore/card/W25CardLimitProgressiveTest.java",
"introducedAt": 25,
"ownership": "PROVIDED_FIXTURE_VERIFIED",
"sha256": "9cdba356b51a1b7c78fad4b1da205f021b67f17705cae12a0382cd835dda6459",
"canonicalTextSha256": "9cdba356b51a1b7c78fad4b1da205f021b67f17705cae12a0382cd835dda6459"
}
],
"authoredTarget": {
"learnerPath": "src/main/java/com/example/financialcore/card/CardAccount.java",
"introducedAt": 25,
"ownership": "LEARNER_AUTHORED",
"starterAsset": "starter/src/main/java/com/example/financialcore/card/CardAccount.java",
"starterSha256": "cc62b9dd28d90f23ada49f810436ed04ce2d604e6b902d72183a7887bbc07ea2",
"starterCanonicalTextSha256": "cc62b9dd28d90f23ada49f810436ed04ce2d604e6b902d72183a7887bbc07ea2",
"solutionAsset": "solution/src/main/java/com/example/financialcore/card/CardAccount.java",
"solutionSha256": "3a142277feffdb89156bbce21dde495d299564a7c1c4a036f7d4505f96fea0e3",
"solutionCanonicalTextSha256": "3a142277feffdb89156bbce21dde495d299564a7c1c4a036f7d4505f96fea0e3"
}
}
05W25CashWalletProgressiveTest — 1_000에서 300 예약
track_learning_stages/securities/w25/tests/src/test/java/com/example/financialcore/securities/W25CashWalletProgressiveTest.java
패키지 정본 보조 계약 · exact JUnit test bytes · 정본 · W25-F0512줄 연결12줄 번역2 chunks
W25CashWalletProgressiveTest — 1_000에서 300 예약
track_learning_stages/securities/w25/tests/src/test/java/com/example/financialcore/securities/W25CashWalletProgressiveTest.java
패키지 정본 보조 계약 · exact JUnit test bytes · 정본 · W25-F05STEP 01 / 13
오늘 이 코드에서 해결할 문제
무엇을 이해해야 하는지 질문부터 잡습니다.
starter의 가용 현금 차감 누락을 Red로 만들고 solution의 available=700·reserved=300을 검증한다.
- open=1_000은 어느 source와 실제 결과에서 확인해야 할까?
- 첫 실패를 만드는 조건과 fail-closed 지점은 어디일까?
- 왜 ‘test 하나에는 assertion 두 개가 있다’를 별도 경계로 남겨야 할까?
open=1_000reserve=300available=700reserved=300W25_SECURITIES_RED_EXPECTED왜 필요한가 — W25CashWalletProgressiveTest — 1_000에서 300 예약
-
open=1_000가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 starter의 가용 현금 차감 누락을 Red로 만들고 solution의 available=700·reserved=300을 검증한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘test 하나에는 assertion 두 개가 있다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 open=1_000와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 02 / 13
아주 짧게: 이 코드는 왜 필요할까?
웹소설 대신 이 코드가 필요한 이유만 두 문단으로 쉽게 봅니다.
사용자의 기본 선택에 따라 이 HTML은 SECURITIES(증권)을 주 트랙으로 읽는다. CARD는 비교용이며 명시적으로 고르면 기본값을 덮어쓸 수 있다. 실제 실행은 최종 선택 한 개를 selected-track.csv·근거·state에 같은 값으로 기록하고 reference와 learner 폴더를 분리한 뒤에만 시작한다. 이 HTML 자체는 Gradle/JUnit을 실행하지 않아 NOT_RUN 상태다.
한 통장만 골라 빨강에서 초록까지 증명하는 일주일
이 파일은 starter의 가용 현금 차감 누락을 Red로 만들고 solution의 available=700·reserved=300을 검증한다. 눈으로 읽을 때는 각 줄을 검수표 한 칸처럼 보고, 입력과 다음 상태를 놓치지 않는다.
마지막 도장은 hash 확인, 세 test phase의 실제 JUnit 실행, XML bytes archive, 사람 review를 서로 구분한 뒤에만 찍는다. Review는 새 test가 아니며 Q41은 stage runtime 밖의 별도 NOT_RUN 과제, sealed official status는 USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED다. 특히 test 하나에는 assertion 두 개가 있다
딱 여기까지만 비유와 SECURITIES 기본 배지는 실제 selected-track 근거, Gradle/JUnit 실행, XML bytes 보존, 사람 review, Q41 실행, sealed official 확인을 대신하지 않는다.
STEP 03 / 13
초등학생도 이해하는 설명
생활 비유와 실제 코드의 경계를 함께 확인합니다.
값 1: open=1_000
이 파일에서 계속 확인할 고정 단서가 open=1_000다.
- 코드 연결
F05 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- test 하나에는 assertion 두 개가 있다
값 2: reserve=300
이 파일에서 계속 확인할 고정 단서가 reserve=300다.
- 코드 연결
F05 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- 0/10_000 finalState를 검증하지 않는다
값 3: available=700
이 파일에서 계속 확인할 고정 단서가 available=700다.
- 코드 연결
F05 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- DB/JPA·동시성은 검증하지 않는다
값 4: reserved=300
이 파일에서 계속 확인할 고정 단서가 reserved=300다.
- 코드 연결
F05 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- reference와 learner root는 서로 달라야 한다
값 5: W25_SECURITIES_RED_EXPECTED
이 파일에서 계속 확인할 고정 단서가 W25_SECURITIES_RED_EXPECTED다.
- 코드 연결
F05 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
STEP 04 / 13
비유 ↔ 코드 전체 연결표
감사 규칙상 연결 대상인 원본 12줄을 빠짐없이 연결합니다.
| 줄 | 정확한 원본 줄 | STARRY 비유 | 실제 뜻·입력·결과·한계 |
|---|---|---|---|
| 1줄F05-L01 | package com. |
출고표 1번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W25CashWalletProgressiveTest.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 3줄F05-L03 | import org. |
출고표 3번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W25CashWalletProgressiveTest.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 4줄F05-L04 | import static org. |
출고표 4번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W25CashWalletProgressiveTest.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 6줄F05-L06 | class W25CashWalletProgressiveTest { |
출고표 6번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 조건·반복·함수의 실행 block을 연다.
|
| 7줄F05-L07 | @Test |
출고표 7번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 JUnit이 실행할 progressive contract test임을 표시한다.
|
| 8줄F05-L08 | void progressive_contract( |
출고표 8번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 선택 트랙의 W25 불변식을 한 개의 점진 test로 검증한다.
|
| 9줄F05-L09 | CashWallet wallet= |
출고표 9번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 가용 현금 1_000으로 securities 지갑을 만든다.
|
| 10줄F05-L10 | wallet. |
출고표 10번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 현금 300을 예약하여 available과 reserved 변화가 함께 일어나게 한다.
|
| 11줄F05-L11 | assertThat( |
출고표 11번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 예약 뒤 가용 현금이 700인지 관찰한다.
|
| 12줄F05-L12 | assertThat( |
출고표 12번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 예약 뒤 예약 현금이 300인지 관찰한다.
|
| 13줄F05-L13 | } |
출고표 13번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 14줄F05-L14 | } |
출고표 14번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
STEP 05 / 13
원본 코드 조각
원본을 2개 의미 조각으로 나누어 그대로 확인합니다.
파일을 한꺼번에 외우지 않고 실행 의미가 이어지는 작은 조각으로 봅니다. 아래 코드는 hash로 고정한 native 정본 source에서 그대로 잘랐습니다.
package com.example.financialcore.securities;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.*;
class W25CashWalletProgressiveTest {
@Test
void progressive_contract() {
CashWallet wallet=CashWallet.open("INV-UNIT",1_000);
wallet.reserve(300);
assertThat(wallet.getAvailableCash()).as("W25_SECURITIES_RED_EXPECTED").isEqualTo(700);
assertThat(wallet.getReservedCash()).isEqualTo(300);
}
}
STEP 06 / 13
코드 한 줄씩 한국어로 번역
비어 있지 않은 12줄을 모두 한국어로 옮깁니다.
비어 있지 않은 원본 줄은 하나도 생략하지 않습니다.
| 줄 | 원본 | 한국어 번역 |
|---|---|---|
| 1 | package com.example.financialcore.securities; | 실행 의미: W25CashWalletProgressiveTest.java의 다음 검증 또는 설명 단계를 구성한다. |
| 3 | import org.junit.jupiter.api.Test; | 실행 의미: W25CashWalletProgressiveTest.java의 다음 검증 또는 설명 단계를 구성한다. |
| 4 | import static org.assertj.core.api.Assertions.*; | 실행 의미: W25CashWalletProgressiveTest.java의 다음 검증 또는 설명 단계를 구성한다. |
| 6 | class W25CashWalletProgressiveTest { | 실행 의미: 조건·반복·함수의 실행 block을 연다. |
| 7 | @Test | 실행 의미: JUnit이 실행할 progressive contract test임을 표시한다. |
| 8 | void progressive_contract() { | 실행 의미: 선택 트랙의 W25 불변식을 한 개의 점진 test로 검증한다. |
| 9 | CashWallet wallet=CashWallet.open("INV-UNIT",1_000); | 실행 의미: 가용 현금 1_000으로 securities 지갑을 만든다. |
| 10 | wallet.reserve(300); | 실행 의미: 현금 300을 예약하여 available과 reserved 변화가 함께 일어나게 한다. |
| 11 | assertThat(wallet.getAvailableCash()).as("W25_SECURITIES_RED_EXPECTED").isEqualTo(700); | 실행 의미: 예약 뒤 가용 현금이 700인지 관찰한다. |
| 12 | assertThat(wallet.getReservedCash()).isEqualTo(300); | 실행 의미: 예약 뒤 예약 현금이 300인지 관찰한다. |
| 13 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 14 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
STEP 07 / 13
기존 수준의 한 줄 읽기·문법 해부
쉬운 설명 다음에 문법과 실행 순서를 정밀하게 읽습니다.
한 줄로 읽기W25CashWalletProgressiveTest — 1_000에서 300 예약는 starter의 가용 현금 차감 누락을 Red로 만들고 solution의 available=700·reserved=300을 검증한다.
문법 해부
- .java 문법에서 선언·조건·pipeline·block 경계를 먼저 나눈다.
- manifest의 finalState와 packaged progressive test의 1_000→700/300 oracle을 서로 다른 계약으로 읽는다.
- phase state·native exit·JUnit XML hash·보존된 XML bytes·사람 판정·USER_ATTESTED external status를 서로 대체하지 않는다.
실행 순서
- 기본 트랙은 SECURITIES(증권)이며, 명시적 CARD 선택은 기본값을 덮어쓴다. 실제 실행 전 최종 선택 한 개를 selected-track.csv·근거·state에 같은 값으로 기록하고 서로 다른 reference/learner root를 확인한다.
- Prepare→VerifyStarter→RecordRed→VerifySolution→RecordGreen→Cumulative→Review 순서를 지킨다.
- test를 소유한 세 phase에서만 native exit와 exact JUnit XML 수치를 판정한다.
- 다음 cleanTest 전에 XML bytes를 고유 경로에 보존하고 runtime history hash와 다시 묶는다. Review·Q41·sealed official evidence는 각자의 별도 owner와 검증 수준으로 남긴다.
W25 조각별 정밀 해설
F05-C01 · 원문 1–12줄
- 문법 해부
- .java 문법으로 1–12줄의 선언·조건·phase·assert block을 나눈다.
- 실제 값 추적
- open=1_000, reserve=300, available=700를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- 기본 SECURITIES 또는 명시적으로 덮어쓴 CARD 중 최종 선택 한 개의 selected-track evidence와 runtime 결과에서 expected와 actual이 일치하고 owner evidence가 같은 run/hash 및 보존 XML에 연결되는 경우다. 기본/덮어쓰기 표시만 있고 실행 evidence가 없으면 NOT_RUN이다.
- 틀린 예·반례
- test 하나에는 assertion 두 개가 있다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- phase 이름·manifest finalState·history hash·exit0 하나를 W25 증거 전체와 같다고 보지 않는다.
- 하지 않는 일
- test 하나에는 assertion 두 개가 있다; 0/10_000 finalState를 검증하지 않는다; DB/JPA·동시성은 검증하지 않는다; reference와 learner root는 서로 달라야 한다; 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다; 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
- 다음 연결
- 다음 조각 또는 F05 evidence 판정으로 상태를 넘긴다.
F05-C02 · 원문 13–14줄
- 문법 해부
- .java 문법으로 13–14줄의 선언·조건·phase·assert block을 나눈다.
- 실제 값 추적
- open=1_000, reserve=300, available=700를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- 기본 SECURITIES 또는 명시적으로 덮어쓴 CARD 중 최종 선택 한 개의 selected-track evidence와 runtime 결과에서 expected와 actual이 일치하고 owner evidence가 같은 run/hash 및 보존 XML에 연결되는 경우다. 기본/덮어쓰기 표시만 있고 실행 evidence가 없으면 NOT_RUN이다.
- 틀린 예·반례
- test 하나에는 assertion 두 개가 있다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- phase 이름·manifest finalState·history hash·exit0 하나를 W25 증거 전체와 같다고 보지 않는다.
- 하지 않는 일
- test 하나에는 assertion 두 개가 있다; 0/10_000 finalState를 검증하지 않는다; DB/JPA·동시성은 검증하지 않는다; reference와 learner root는 서로 달라야 한다; 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다; 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
- 다음 연결
- 다음 조각 또는 F05 evidence 판정으로 상태를 넘긴다.
실행 순서 — W25CashWalletProgressiveTest — 1_000에서 300 예약
-
reserve=300가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 starter의 가용 현금 차감 누락을 Red로 만들고 solution의 available=700·reserved=300을 검증한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘0/10_000 finalState를 검증하지 않는다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 reserve=300와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 08 / 13
실제 값 따라가기
같은 입력값이 어느 줄을 지나 어떤 결과가 되는지 추적합니다.
| 순서 | 들어온 값 | 코드가 하는 일 | 나온 값·상태 | 경계 |
|---|---|---|---|---|
| 입력 | open=1_000 | source 계약에 대입 | F05 실행/설명 시작 상태 | test 하나에는 assertion 두 개가 있다 |
| 검증 | reserve=300 | expected와 actual 또는 형식 대조 | 통과 또는 첫 mismatch | 0/10_000 finalState를 검증하지 않는다 |
| 증거 | W25_SECURITIES_RED_EXPECTED | marker·hash·row를 같은 run에 연결 | 범위가 적힌 evidence 후보 | 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다 |
실제 값 — W25CashWalletProgressiveTest — 1_000에서 300 예약
-
available=700가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 starter의 가용 현금 차감 누락을 Red로 만들고 solution의 available=700·reserved=300을 검증한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘DB/JPA·동시성은 검증하지 않는다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 available=700와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 09 / 13
Gradle·JUnit XML·PowerShell·SQL 내부에서 벌어지는 일
세 test phase, XML bytes archive, Review, 별도 Q41, USER_ATTESTED sealed 결과의 owner와 증명 범위를 구분합니다.
W25CashWalletProgressiveTest.java bytes와 track·phase·hash 계약을 읽는다.
SECURITIES 기본 선택과 파일 존재·phase 이름만으로 runtime Green을 주장할 수 없다. 실제 selected-track evidence와 실행 결과는 별도다.RecordRed·RecordGreen·Cumulative에서만 native exit와 exact JUnit XML을 만든다.
test 하나에는 assertion 두 개가 있다XML bytes를 고유 파일로 보존하고 history hash와 묶은 뒤, Review는 기존 CumulativeGreen만 인용한다. Q41은 별도 PostgreSQL evidence, sealed official status는 user-attested evidence로 남긴다.
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다이 파일의 @Test가 실제로 고정하는 범위
progressive_contract
- 선택 트랙 객체를 1_000으로 생성한다.
- SECURITIES는 reserve(300), CARD는 hold(300)을 한 번 호출한다.
- 두 잔액이 각각 700과 300이고 failures/errors/skipped가 모두 0인지 본다.
- packaged 1_000→700/300 예시에서 두 상태 값이 함께 갱신된다.
- manifest의 10_000 finalState
- 반대 트랙 또는 실제 track 선택
- XML bytes의 장기 보존
- Review의 새 실행·Q41 Green·sealed official truth
첫 실패 경계 starter에서는 available 차감 또는 used 증가 누락 때문에 선택 트랙 redMarker assertion이 먼저 실패한다.
첫 실패 경계 — W25CashWalletProgressiveTest — 1_000에서 300 예약
-
reserved=300가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 starter의 가용 현금 차감 누락을 Red로 만들고 solution의 available=700·reserved=300을 검증한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘reference와 learner root는 서로 달라야 한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 reserved=300와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 10 / 13
흔한 착각과 틀린 예
그럴듯하지만 틀린 해석을 반례로 고칩니다.
❌ Prepare·VerifyStarter·VerifySolution·Review도 Gradle을 실행해 Green을 만든다.
왜 틀리나 runtime에서 test 실행을 소유하는 phase는 RecordRed·RecordGreen·Cumulative뿐이다.
바르게 읽기 각 phase history의 execution 유무와 mode를 직접 확인한다.
반례 VerifySolution은 solution hash만 검증하므로 새 JUnit XML이 없어야 정상이다.
❌ 기본 트랙이 SECURITIES이므로 CARD도 함께 실행해도 되고, 기본 배지만으로 runtime 선택·실행 증거가 완성된다.
왜 틀리나 W25 계약은 실제 사용자 근거가 있는 선택 트랙 하나와 반대 트랙 leak 부재를 요구한다.
바르게 읽기 기본 선택은 SECURITIES(증권)이며 명시적 CARD 선택은 덮어쓰기다. 실행 전 최종 선택 한 개를 selected-track.csv·근거·state에 같은 값으로 고정한다.
반례 SECURITIES 기본 배지만 보고 test 실행을 주장하거나 두 트랙 test가 함께 보이면 선택 경계를 위반한다.
❌ progressive_contract Green이면 manifest의 finalState 10_000도 증명된다.
왜 틀리나 packaged test는 1_000에서 300을 처리한 700/300만 assert한다.
바르게 읽기 10_000 finalState는 별도 learner test 또는 사람이 결박한 evidence로 증명한다.
반례 runtime은 domainContract.finalState 문자열을 parse하거나 assert하지 않는다.
❌ history에 XML SHA가 있으니 Red·Green·Cumulative XML 원본이 모두 보존됐다.
왜 틀리나 다음 cleanTest가 build/test-results의 이전 XML을 덮어쓰며 state는 bytes를 복사하지 않는다.
바르게 읽기 각 phase 직후 고유 evidence 경로로 원자 복사하고 hash를 history와 대조한다.
반례 RecordGreen 뒤에는 Red XML 경로가 사라질 수 있다.
❌ Review가 새 test를 실행해 CumulativeGreen을 다시 만들고 Q41·sealed official 결과까지 자동 확인한다.
왜 틀리나 Review는 기존 CumulativeGreen을 전제로 review entry와 leak check만 기록한다. Q41은 별도 PostgreSQL 과제이고 sealed official status는 user-attested다.
바르게 읽기 Review에서는 reviewedPhase와 history 증가만 보고, Q41 native evidence와 USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED sealed evidence를 별도로 판정한다.
반례 Review 뒤 phase는 여전히 CumulativeGreen이고 새 execution/XML·Q41 transcript·official login verification이 생기지 않는다.
STEP 11 / 13
이 코드가 보장하지 않는 것
선택 미결정·10_000 finalState·XML 보존·Review/Q41/sealed official truth처럼 이 코드가 책임지지 않는 일을 분리합니다.
test 하나에는 assertion 두 개가 있다
이 책임을 맡는 곳: runtime Gate0/10_000 finalState를 검증하지 않는다
이 책임을 맡는 곳: external/human reviewDB/JPA·동시성은 검증하지 않는다
이 책임을 맡는 곳: release manifestreference와 learner root는 서로 달라야 한다
이 책임을 맡는 곳: 운영 환경증명하지 않는 범위 — W25CashWalletProgressiveTest — 1_000에서 300 예약
-
W25_SECURITIES_RED_EXPECTED가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 starter의 가용 현금 차감 누락을 Red로 만들고 solution의 available=700·reserved=300을 검증한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 W25_SECURITIES_RED_EXPECTED와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 12 / 13
직접 다시 써보기
뜻 → 조각 → 전체 코드 순서로 다시 씁니다.
1단계 · 뜻부터 복원
- starter의 가용 현금 차감 누락을 Red로 만들고 solution의 available=700·reserved=300을 검증한다.
- 핵심 값은 open=1_000, reserve=300, available=700, reserved=300, W25_SECURITIES_RED_EXPECTED다.
2단계 · 코드 조각 재조립
- 1. W25CashWalletProgressiveTest.java의 다음 검증 또는 설명 단계를 구성한다
- 3. W25CashWalletProgressiveTest.java의 다음 검증 또는 설명 단계를 구성한다
- 4. W25CashWalletProgressiveTest.java의 다음 검증 또는 설명 단계를 구성한다
- 6. 조건·반복·함수의 실행 block을 연다
- 7. JUnit이 실행할 progressive contract test임을 표시한다
- 8. 선택 트랙의 W25 불변식을 한 개의 점진 test로 검증한다
- 9. 가용 현금 1_000으로 securities 지갑을 만든다
- 10. 현금 300을 예약하여 available과 reserved 변화가 함께 일어나게 한다
3단계 · 파일 전체 다시 쓰기
track_learning_stages/securities/w25/tests/src/test/java/com/example/financialcore/securities/W25CashWalletProgressiveTest.java을 새 파일에 다시 쓰고 expected·actual·실패·cleanup·비범위를 주석으로 표시한다.
자가 점검
- 비어 있지 않은 모든 source 줄을 한 번씩 읽었나?
- 기본 트랙을 SECURITIES(증권) 하나로 두고 기본 선택·selected-track evidence·runtime Green을 서로 분리했나?
- Review·Q41·USER_ATTESTED sealed 상태를 자동 성공으로 꾸미지 않았나?
- XML bytes archive와 첫 실패·cleanup 책임을 설명할 수 있나?
STEP 13 / 13
전체 원본 source
감사로 고정한 전체 source를 가감 없이 확인합니다.
원문 정본 전체 source 확인하기
package com.example.financialcore.securities;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.*;
class W25CashWalletProgressiveTest {
@Test
void progressive_contract() {
CashWallet wallet=CashWallet.open("INV-UNIT",1_000);
wallet.reserve(300);
assertThat(wallet.getAvailableCash()).as("W25_SECURITIES_RED_EXPECTED").isEqualTo(700);
assertThat(wallet.getReservedCash()).isEqualTo(300);
}
}
06W25CardLimitProgressiveTest — 1_000에서 300 hold
track_learning_stages/card/w25/tests/src/test/java/com/example/financialcore/card/W25CardLimitProgressiveTest.java
패키지 정본 보조 계약 · exact JUnit test bytes · 정본 · W25-F0611줄 연결11줄 번역2 chunks
W25CardLimitProgressiveTest — 1_000에서 300 hold
track_learning_stages/card/w25/tests/src/test/java/com/example/financialcore/card/W25CardLimitProgressiveTest.java
패키지 정본 보조 계약 · exact JUnit test bytes · 정본 · W25-F06STEP 01 / 13
오늘 이 코드에서 해결할 문제
무엇을 이해해야 하는지 질문부터 잡습니다.
starter의 사용액 증가 누락을 Red로 만들고 solution의 used=300·available=700을 검증한다.
- open=1_000은 어느 source와 실제 결과에서 확인해야 할까?
- 첫 실패를 만드는 조건과 fail-closed 지점은 어디일까?
- 왜 ‘test 하나에는 assertion 두 개가 있다’를 별도 경계로 남겨야 할까?
open=1_000hold=300used=300available=700W25_CARD_RED_EXPECTED왜 필요한가 — W25CardLimitProgressiveTest — 1_000에서 300 hold
-
open=1_000가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 starter의 사용액 증가 누락을 Red로 만들고 solution의 used=300·available=700을 검증한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘test 하나에는 assertion 두 개가 있다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 open=1_000와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 02 / 13
아주 짧게: 이 코드는 왜 필요할까?
웹소설 대신 이 코드가 필요한 이유만 두 문단으로 쉽게 봅니다.
사용자의 기본 선택에 따라 이 HTML은 SECURITIES(증권)을 주 트랙으로 읽는다. CARD는 비교용이며 명시적으로 고르면 기본값을 덮어쓸 수 있다. 실제 실행은 최종 선택 한 개를 selected-track.csv·근거·state에 같은 값으로 기록하고 reference와 learner 폴더를 분리한 뒤에만 시작한다. 이 HTML 자체는 Gradle/JUnit을 실행하지 않아 NOT_RUN 상태다.
한 통장만 골라 빨강에서 초록까지 증명하는 일주일
이 파일은 starter의 사용액 증가 누락을 Red로 만들고 solution의 used=300·available=700을 검증한다. 눈으로 읽을 때는 각 줄을 검수표 한 칸처럼 보고, 입력과 다음 상태를 놓치지 않는다.
마지막 도장은 hash 확인, 세 test phase의 실제 JUnit 실행, XML bytes archive, 사람 review를 서로 구분한 뒤에만 찍는다. Review는 새 test가 아니며 Q41은 stage runtime 밖의 별도 NOT_RUN 과제, sealed official status는 USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED다. 특히 test 하나에는 assertion 두 개가 있다
딱 여기까지만 비유와 SECURITIES 기본 배지는 실제 selected-track 근거, Gradle/JUnit 실행, XML bytes 보존, 사람 review, Q41 실행, sealed official 확인을 대신하지 않는다.
STEP 03 / 13
초등학생도 이해하는 설명
생활 비유와 실제 코드의 경계를 함께 확인합니다.
값 1: open=1_000
이 파일에서 계속 확인할 고정 단서가 open=1_000다.
- 코드 연결
F06 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- test 하나에는 assertion 두 개가 있다
값 2: hold=300
이 파일에서 계속 확인할 고정 단서가 hold=300다.
- 코드 연결
F06 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- 0/10_000 finalState를 검증하지 않는다
값 3: used=300
이 파일에서 계속 확인할 고정 단서가 used=300다.
- 코드 연결
F06 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- DB/JPA·동시성은 검증하지 않는다
값 4: available=700
이 파일에서 계속 확인할 고정 단서가 available=700다.
- 코드 연결
F06 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- reference와 learner root는 서로 달라야 한다
값 5: W25_CARD_RED_EXPECTED
이 파일에서 계속 확인할 고정 단서가 W25_CARD_RED_EXPECTED다.
- 코드 연결
F06 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
STEP 04 / 13
비유 ↔ 코드 전체 연결표
감사 규칙상 연결 대상인 원본 11줄을 빠짐없이 연결합니다.
| 줄 | 정확한 원본 줄 | STARRY 비유 | 실제 뜻·입력·결과·한계 |
|---|---|---|---|
| 1줄F06-L01 | package com. |
출고표 1번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W25CardLimitProgressiveTest.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 3줄F06-L03 | import org. |
출고표 3번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W25CardLimitProgressiveTest.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 4줄F06-L04 | import static org. |
출고표 4번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W25CardLimitProgressiveTest.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 6줄F06-L06 | class W25CardLimitProgressiveTest { |
출고표 6번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 조건·반복·함수의 실행 block을 연다.
|
| 7줄F06-L07 | @Test |
출고표 7번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 JUnit이 실행할 progressive contract test임을 표시한다.
|
| 8줄F06-L08 | void progressive_contract( |
출고표 8번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 선택 트랙의 W25 불변식을 한 개의 점진 test로 검증한다.
|
| 9줄F06-L09 | CardAccount account= |
출고표 9번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 신용 한도 1_000으로 card 계정을 만든다.
|
| 10줄F06-L10 | assertThat( |
출고표 10번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 hold 뒤 사용액이 300인지 관찰한다.
|
| 11줄F06-L11 | assertThat( |
출고표 11번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 hold 뒤 가용 한도가 700인지 관찰한다.
|
| 12줄F06-L12 | } |
출고표 12번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 13줄F06-L13 | } |
출고표 13번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
STEP 05 / 13
원본 코드 조각
원본을 2개 의미 조각으로 나누어 그대로 확인합니다.
파일을 한꺼번에 외우지 않고 실행 의미가 이어지는 작은 조각으로 봅니다. 아래 코드는 hash로 고정한 native 정본 source에서 그대로 잘랐습니다.
package com.example.financialcore.card;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.*;
class W25CardLimitProgressiveTest {
@Test
void progressive_contract() {
CardAccount account=CardAccount.open("CARD-UNIT",1_000);account.hold(300);
assertThat(account.getUsedAmount()).as("W25_CARD_RED_EXPECTED").isEqualTo(300);
assertThat(account.availableAmount()).isEqualTo(700);
}
}
STEP 06 / 13
코드 한 줄씩 한국어로 번역
비어 있지 않은 11줄을 모두 한국어로 옮깁니다.
비어 있지 않은 원본 줄은 하나도 생략하지 않습니다.
| 줄 | 원본 | 한국어 번역 |
|---|---|---|
| 1 | package com.example.financialcore.card; | 실행 의미: W25CardLimitProgressiveTest.java의 다음 검증 또는 설명 단계를 구성한다. |
| 3 | import org.junit.jupiter.api.Test; | 실행 의미: W25CardLimitProgressiveTest.java의 다음 검증 또는 설명 단계를 구성한다. |
| 4 | import static org.assertj.core.api.Assertions.*; | 실행 의미: W25CardLimitProgressiveTest.java의 다음 검증 또는 설명 단계를 구성한다. |
| 6 | class W25CardLimitProgressiveTest { | 실행 의미: 조건·반복·함수의 실행 block을 연다. |
| 7 | @Test | 실행 의미: JUnit이 실행할 progressive contract test임을 표시한다. |
| 8 | void progressive_contract() { | 실행 의미: 선택 트랙의 W25 불변식을 한 개의 점진 test로 검증한다. |
| 9 | CardAccount account=CardAccount.open("CARD-UNIT",1_000);account.hold(300); | 실행 의미: 신용 한도 1_000으로 card 계정을 만든다. |
| 10 | assertThat(account.getUsedAmount()).as("W25_CARD_RED_EXPECTED").isEqualTo(300); | 실행 의미: hold 뒤 사용액이 300인지 관찰한다. |
| 11 | assertThat(account.availableAmount()).isEqualTo(700); | 실행 의미: hold 뒤 가용 한도가 700인지 관찰한다. |
| 12 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 13 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
STEP 07 / 13
기존 수준의 한 줄 읽기·문법 해부
쉬운 설명 다음에 문법과 실행 순서를 정밀하게 읽습니다.
한 줄로 읽기W25CardLimitProgressiveTest — 1_000에서 300 hold는 starter의 사용액 증가 누락을 Red로 만들고 solution의 used=300·available=700을 검증한다.
문법 해부
- .java 문법에서 선언·조건·pipeline·block 경계를 먼저 나눈다.
- manifest의 finalState와 packaged progressive test의 1_000→700/300 oracle을 서로 다른 계약으로 읽는다.
- phase state·native exit·JUnit XML hash·보존된 XML bytes·사람 판정·USER_ATTESTED external status를 서로 대체하지 않는다.
실행 순서
- 기본 트랙은 SECURITIES(증권)이며, 명시적 CARD 선택은 기본값을 덮어쓴다. 실제 실행 전 최종 선택 한 개를 selected-track.csv·근거·state에 같은 값으로 기록하고 서로 다른 reference/learner root를 확인한다.
- Prepare→VerifyStarter→RecordRed→VerifySolution→RecordGreen→Cumulative→Review 순서를 지킨다.
- test를 소유한 세 phase에서만 native exit와 exact JUnit XML 수치를 판정한다.
- 다음 cleanTest 전에 XML bytes를 고유 경로에 보존하고 runtime history hash와 다시 묶는다. Review·Q41·sealed official evidence는 각자의 별도 owner와 검증 수준으로 남긴다.
W25 조각별 정밀 해설
F06-C01 · 원문 1–12줄
- 문법 해부
- .java 문법으로 1–12줄의 선언·조건·phase·assert block을 나눈다.
- 실제 값 추적
- open=1_000, hold=300, used=300를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- 기본 SECURITIES 또는 명시적으로 덮어쓴 CARD 중 최종 선택 한 개의 selected-track evidence와 runtime 결과에서 expected와 actual이 일치하고 owner evidence가 같은 run/hash 및 보존 XML에 연결되는 경우다. 기본/덮어쓰기 표시만 있고 실행 evidence가 없으면 NOT_RUN이다.
- 틀린 예·반례
- test 하나에는 assertion 두 개가 있다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- phase 이름·manifest finalState·history hash·exit0 하나를 W25 증거 전체와 같다고 보지 않는다.
- 하지 않는 일
- test 하나에는 assertion 두 개가 있다; 0/10_000 finalState를 검증하지 않는다; DB/JPA·동시성은 검증하지 않는다; reference와 learner root는 서로 달라야 한다; 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다; 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
- 다음 연결
- 다음 조각 또는 F06 evidence 판정으로 상태를 넘긴다.
F06-C02 · 원문 13–13줄
- 문법 해부
- .java 문법으로 13–13줄의 선언·조건·phase·assert block을 나눈다.
- 실제 값 추적
- open=1_000, hold=300, used=300를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- 기본 SECURITIES 또는 명시적으로 덮어쓴 CARD 중 최종 선택 한 개의 selected-track evidence와 runtime 결과에서 expected와 actual이 일치하고 owner evidence가 같은 run/hash 및 보존 XML에 연결되는 경우다. 기본/덮어쓰기 표시만 있고 실행 evidence가 없으면 NOT_RUN이다.
- 틀린 예·반례
- test 하나에는 assertion 두 개가 있다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- phase 이름·manifest finalState·history hash·exit0 하나를 W25 증거 전체와 같다고 보지 않는다.
- 하지 않는 일
- test 하나에는 assertion 두 개가 있다; 0/10_000 finalState를 검증하지 않는다; DB/JPA·동시성은 검증하지 않는다; reference와 learner root는 서로 달라야 한다; 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다; 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
- 다음 연결
- 다음 조각 또는 F06 evidence 판정으로 상태를 넘긴다.
실행 순서 — W25CardLimitProgressiveTest — 1_000에서 300 hold
-
hold=300가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 starter의 사용액 증가 누락을 Red로 만들고 solution의 used=300·available=700을 검증한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘0/10_000 finalState를 검증하지 않는다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 hold=300와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 08 / 13
실제 값 따라가기
같은 입력값이 어느 줄을 지나 어떤 결과가 되는지 추적합니다.
| 순서 | 들어온 값 | 코드가 하는 일 | 나온 값·상태 | 경계 |
|---|---|---|---|---|
| 입력 | open=1_000 | source 계약에 대입 | F06 실행/설명 시작 상태 | test 하나에는 assertion 두 개가 있다 |
| 검증 | hold=300 | expected와 actual 또는 형식 대조 | 통과 또는 첫 mismatch | 0/10_000 finalState를 검증하지 않는다 |
| 증거 | W25_CARD_RED_EXPECTED | marker·hash·row를 같은 run에 연결 | 범위가 적힌 evidence 후보 | 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다 |
실제 값 — W25CardLimitProgressiveTest — 1_000에서 300 hold
-
used=300가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 starter의 사용액 증가 누락을 Red로 만들고 solution의 used=300·available=700을 검증한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘DB/JPA·동시성은 검증하지 않는다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 used=300와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 09 / 13
Gradle·JUnit XML·PowerShell·SQL 내부에서 벌어지는 일
세 test phase, XML bytes archive, Review, 별도 Q41, USER_ATTESTED sealed 결과의 owner와 증명 범위를 구분합니다.
W25CardLimitProgressiveTest.java bytes와 track·phase·hash 계약을 읽는다.
SECURITIES 기본 선택과 파일 존재·phase 이름만으로 runtime Green을 주장할 수 없다. 실제 selected-track evidence와 실행 결과는 별도다.RecordRed·RecordGreen·Cumulative에서만 native exit와 exact JUnit XML을 만든다.
test 하나에는 assertion 두 개가 있다XML bytes를 고유 파일로 보존하고 history hash와 묶은 뒤, Review는 기존 CumulativeGreen만 인용한다. Q41은 별도 PostgreSQL evidence, sealed official status는 user-attested evidence로 남긴다.
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다이 파일의 @Test가 실제로 고정하는 범위
progressive_contract
- 선택 트랙 객체를 1_000으로 생성한다.
- SECURITIES는 reserve(300), CARD는 hold(300)을 한 번 호출한다.
- 두 잔액이 각각 700과 300이고 failures/errors/skipped가 모두 0인지 본다.
- packaged 1_000→700/300 예시에서 두 상태 값이 함께 갱신된다.
- manifest의 10_000 finalState
- 반대 트랙 또는 실제 track 선택
- XML bytes의 장기 보존
- Review의 새 실행·Q41 Green·sealed official truth
첫 실패 경계 starter에서는 available 차감 또는 used 증가 누락 때문에 선택 트랙 redMarker assertion이 먼저 실패한다.
첫 실패 경계 — W25CardLimitProgressiveTest — 1_000에서 300 hold
-
available=700가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 starter의 사용액 증가 누락을 Red로 만들고 solution의 used=300·available=700을 검증한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘reference와 learner root는 서로 달라야 한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 available=700와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 10 / 13
흔한 착각과 틀린 예
그럴듯하지만 틀린 해석을 반례로 고칩니다.
❌ Prepare·VerifyStarter·VerifySolution·Review도 Gradle을 실행해 Green을 만든다.
왜 틀리나 runtime에서 test 실행을 소유하는 phase는 RecordRed·RecordGreen·Cumulative뿐이다.
바르게 읽기 각 phase history의 execution 유무와 mode를 직접 확인한다.
반례 VerifySolution은 solution hash만 검증하므로 새 JUnit XML이 없어야 정상이다.
❌ 기본 트랙이 SECURITIES이므로 CARD도 함께 실행해도 되고, 기본 배지만으로 runtime 선택·실행 증거가 완성된다.
왜 틀리나 W25 계약은 실제 사용자 근거가 있는 선택 트랙 하나와 반대 트랙 leak 부재를 요구한다.
바르게 읽기 기본 선택은 SECURITIES(증권)이며 명시적 CARD 선택은 덮어쓰기다. 실행 전 최종 선택 한 개를 selected-track.csv·근거·state에 같은 값으로 고정한다.
반례 SECURITIES 기본 배지만 보고 test 실행을 주장하거나 두 트랙 test가 함께 보이면 선택 경계를 위반한다.
❌ progressive_contract Green이면 manifest의 finalState 10_000도 증명된다.
왜 틀리나 packaged test는 1_000에서 300을 처리한 700/300만 assert한다.
바르게 읽기 10_000 finalState는 별도 learner test 또는 사람이 결박한 evidence로 증명한다.
반례 runtime은 domainContract.finalState 문자열을 parse하거나 assert하지 않는다.
❌ history에 XML SHA가 있으니 Red·Green·Cumulative XML 원본이 모두 보존됐다.
왜 틀리나 다음 cleanTest가 build/test-results의 이전 XML을 덮어쓰며 state는 bytes를 복사하지 않는다.
바르게 읽기 각 phase 직후 고유 evidence 경로로 원자 복사하고 hash를 history와 대조한다.
반례 RecordGreen 뒤에는 Red XML 경로가 사라질 수 있다.
❌ Review가 새 test를 실행해 CumulativeGreen을 다시 만들고 Q41·sealed official 결과까지 자동 확인한다.
왜 틀리나 Review는 기존 CumulativeGreen을 전제로 review entry와 leak check만 기록한다. Q41은 별도 PostgreSQL 과제이고 sealed official status는 user-attested다.
바르게 읽기 Review에서는 reviewedPhase와 history 증가만 보고, Q41 native evidence와 USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED sealed evidence를 별도로 판정한다.
반례 Review 뒤 phase는 여전히 CumulativeGreen이고 새 execution/XML·Q41 transcript·official login verification이 생기지 않는다.
STEP 11 / 13
이 코드가 보장하지 않는 것
선택 미결정·10_000 finalState·XML 보존·Review/Q41/sealed official truth처럼 이 코드가 책임지지 않는 일을 분리합니다.
test 하나에는 assertion 두 개가 있다
이 책임을 맡는 곳: runtime Gate0/10_000 finalState를 검증하지 않는다
이 책임을 맡는 곳: external/human reviewDB/JPA·동시성은 검증하지 않는다
이 책임을 맡는 곳: release manifestreference와 learner root는 서로 달라야 한다
이 책임을 맡는 곳: 운영 환경증명하지 않는 범위 — W25CardLimitProgressiveTest — 1_000에서 300 hold
-
W25_CARD_RED_EXPECTED가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 starter의 사용액 증가 누락을 Red로 만들고 solution의 used=300·available=700을 검증한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 W25_CARD_RED_EXPECTED와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 12 / 13
직접 다시 써보기
뜻 → 조각 → 전체 코드 순서로 다시 씁니다.
1단계 · 뜻부터 복원
- starter의 사용액 증가 누락을 Red로 만들고 solution의 used=300·available=700을 검증한다.
- 핵심 값은 open=1_000, hold=300, used=300, available=700, W25_CARD_RED_EXPECTED다.
2단계 · 코드 조각 재조립
- 1. W25CardLimitProgressiveTest.java의 다음 검증 또는 설명 단계를 구성한다
- 3. W25CardLimitProgressiveTest.java의 다음 검증 또는 설명 단계를 구성한다
- 4. W25CardLimitProgressiveTest.java의 다음 검증 또는 설명 단계를 구성한다
- 6. 조건·반복·함수의 실행 block을 연다
- 7. JUnit이 실행할 progressive contract test임을 표시한다
- 8. 선택 트랙의 W25 불변식을 한 개의 점진 test로 검증한다
- 9. 신용 한도 1_000으로 card 계정을 만든다
- 10. hold 뒤 사용액이 300인지 관찰한다
3단계 · 파일 전체 다시 쓰기
track_learning_stages/card/w25/tests/src/test/java/com/example/financialcore/card/W25CardLimitProgressiveTest.java을 새 파일에 다시 쓰고 expected·actual·실패·cleanup·비범위를 주석으로 표시한다.
자가 점검
- 비어 있지 않은 모든 source 줄을 한 번씩 읽었나?
- 기본 트랙을 SECURITIES(증권) 하나로 두고 기본 선택·selected-track evidence·runtime Green을 서로 분리했나?
- Review·Q41·USER_ATTESTED sealed 상태를 자동 성공으로 꾸미지 않았나?
- XML bytes archive와 첫 실패·cleanup 책임을 설명할 수 있나?
STEP 13 / 13
전체 원본 source
감사로 고정한 전체 source를 가감 없이 확인합니다.
원문 정본 전체 source 확인하기
package com.example.financialcore.card;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.*;
class W25CardLimitProgressiveTest {
@Test
void progressive_contract() {
CardAccount account=CardAccount.open("CARD-UNIT",1_000);account.hold(300);
assertThat(account.getUsedAmount()).as("W25_CARD_RED_EXPECTED").isEqualTo(300);
assertThat(account.availableAmount()).isEqualTo(700);
}
}
07D1 Prepare — 선택 근거와 Prepared state
illustrative/powershell/W25-D1-prepare.ps1
학습용 예시 · W25 phase wrapper · 정본 답안 아님 · 로컬 미실행 · 학습용 예시 · 정본 답안 아님 · NOT_RUN · W25-F0736줄 연결36줄 번역4 chunks
D1 Prepare — 선택 근거와 Prepared state
illustrative/powershell/W25-D1-prepare.ps1
학습용 예시 · W25 phase wrapper · 정본 답안 아님 · 로컬 미실행 · 학습용 예시 · 정본 답안 아님 · NOT_RUN · W25-F07STEP 01 / 13
오늘 이 코드에서 해결할 문제
무엇을 이해해야 하는지 질문부터 잡습니다.
FINANCIAL_IT_SELECTED_TRACK이 비어 있으면 SECURITIES를 기본값으로 사용하고 exactly one selected-track.csv를 만든 뒤 Prepare가 test fixture·leak 경계만 검증했는지 확인한다.
- default=SECURITIES은 어느 source와 실제 결과에서 확인해야 할까?
- 첫 실패를 만드는 조건과 fail-closed 지점은 어디일까?
- 왜 ‘SECURITIES 기본 선택은 runtime 실행 결과가 아니다’를 별도 경계로 남겨야 할까?
default=SECURITIESSECURITIES xor CARDselected-track.csvPreparedruntime_claim=false왜 필요한가 — D1 Prepare — 선택 근거와 Prepared state
-
default=SECURITIES가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 FINANCIAL_IT_SELECTED_TRACK이 비어 있으면 SECURITIES를 기본값으로 사용하고 exactly one selected-track.csv를 만든 뒤 Prepare가 test fixture·leak 경계만 검증했는지 확인한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘SECURITIES 기본 선택은 runtime 실행 결과가 아니다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 default=SECURITIES와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 02 / 13
아주 짧게: 이 코드는 왜 필요할까?
웹소설 대신 이 코드가 필요한 이유만 두 문단으로 쉽게 봅니다.
사용자의 기본 선택에 따라 이 HTML은 SECURITIES(증권)을 주 트랙으로 읽는다. CARD는 비교용이며 명시적으로 고르면 기본값을 덮어쓸 수 있다. 실제 실행은 최종 선택 한 개를 selected-track.csv·근거·state에 같은 값으로 기록하고 reference와 learner 폴더를 분리한 뒤에만 시작한다. 이 HTML 자체는 Gradle/JUnit을 실행하지 않아 NOT_RUN 상태다.
한 통장만 골라 빨강에서 초록까지 증명하는 일주일
이 파일은 FINANCIAL_IT_SELECTED_TRACK이 비어 있으면 SECURITIES를 기본값으로 사용하고 exactly one selected-track.csv를 만든 뒤 Prepare가 test fixture·leak 경계만 검증했는지 확인한다. 눈으로 읽을 때는 각 줄을 검수표 한 칸처럼 보고, 입력과 다음 상태를 놓치지 않는다.
마지막 도장은 hash 확인, 세 test phase의 실제 JUnit 실행, XML bytes archive, 사람 review를 서로 구분한 뒤에만 찍는다. Review는 새 test가 아니며 Q41은 stage runtime 밖의 별도 NOT_RUN 과제, sealed official status는 USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED다. 특히 SECURITIES 기본 선택은 runtime 실행 결과가 아니다
딱 여기까지만 비유와 SECURITIES 기본 배지는 실제 selected-track 근거, Gradle/JUnit 실행, XML bytes 보존, 사람 review, Q41 실행, sealed official 확인을 대신하지 않는다.
STEP 03 / 13
초등학생도 이해하는 설명
생활 비유와 실제 코드의 경계를 함께 확인합니다.
값 1: default=SECURITIES
이 파일에서 계속 확인할 고정 단서가 default=SECURITIES다.
- 코드 연결
F07 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- SECURITIES 기본 선택은 runtime 실행 결과가 아니다
값 2: SECURITIES xor CARD
이 파일에서 계속 확인할 고정 단서가 SECURITIES xor CARD다.
- 코드 연결
F07 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- Prepare는 target hash·Gradle·XML·finalState를 검증하지 않는다
값 3: selected-track.csv
이 파일에서 계속 확인할 고정 단서가 selected-track.csv다.
- 코드 연결
F07 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- reference와 learner root는 서로 달라야 한다
값 4: Prepared
이 파일에서 계속 확인할 고정 단서가 Prepared다.
- 코드 연결
F07 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
값 5: runtime_claim=false
이 파일에서 계속 확인할 고정 단서가 runtime_claim=false다.
- 코드 연결
F07 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
STEP 04 / 13
비유 ↔ 코드 전체 연결표
감사 규칙상 연결 대상인 원본 36줄을 빠짐없이 연결합니다.
| 줄 | 정확한 원본 줄 | STARRY 비유 | 실제 뜻·입력·결과·한계 |
|---|---|---|---|
| 1줄F07-L01 | # W25 PDF p3-p7의 Prepare 흐름을 읽기 좋게 정리한 학습용 예시다. |
출고표 1번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다.
|
| 2줄F07-L02 | # packaged reference source가 아니며, |
출고표 2번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다.
|
| 3줄F07-L03 | $ErrorActionPreference = |
출고표 3번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 PowerShell 오류를 계속 진행하지 않고 중단시키는 기본 정책을 둔다.
|
| 5줄F07-L05 | foreach ( |
출고표 5번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 고정 목록의 각 항목에 같은 검사를 반복 적용한다.
|
| 6줄F07-L06 | $Value = |
출고표 6번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 7줄F07-L07 | if ( |
출고표 7번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 8줄F07-L08 | } |
출고표 8번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 9줄F07-L09 | $ReferenceRoot = |
출고표 9번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 입력 경로를 실제 절대 경로로 확인한다.
|
| 10줄F07-L10 | $LearnerRoot = |
출고표 10번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 입력 경로를 실제 절대 경로로 확인한다.
|
| 11줄F07-L11 | if ( |
출고표 11번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 조건·반복·함수의 실행 block을 연다.
|
| 12줄F07-L12 | throw 'reference and learner roots must be different' |
출고표 12번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 13줄F07-L13 | } |
출고표 13번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 14줄F07-L14 | $TrackValue = |
출고표 14번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 15줄F07-L15 | $Track = |
출고표 15번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 16줄F07-L16 | if ( |
출고표 16번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 17줄F07-L17 | if ( |
출고표 17번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 조건·반복·함수의 실행 block을 연다.
|
| 18줄F07-L18 | throw 'FINANCIAL_IT_TRACK_RATIONALE must contain the learner decision' |
출고표 18번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 19줄F07-L19 | } |
출고표 19번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 21줄F07-L21 | $EvidenceDir = |
출고표 21번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 22줄F07-L22 | New-Item -ItemType Directory -Force -Path $EvidenceDir | Out-Null |
출고표 22번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 Markdown 표 또는 PowerShell pipeline에서 값을 열이나 다음 명령으로 연결한다.
|
| 23줄F07-L23 | [ |
출고표 23번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 조건·반복·함수의 실행 block을 연다.
|
| 24줄F07-L24 | selected_track = |
출고표 24번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W25-D1-prepare.ps1의 다음 검증 또는 설명 단계를 구성한다.
|
| 25줄F07-L25 | decided_at = |
출고표 25번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W25-D1-prepare.ps1의 다음 검증 또는 설명 단계를 구성한다.
|
| 26줄F07-L26 | rationale = |
출고표 26번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W25-D1-prepare.ps1의 다음 검증 또는 설명 단계를 구성한다.
|
| 27줄F07-L27 | evidence = |
출고표 27번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W25-D1-prepare.ps1의 다음 검증 또는 설명 단계를 구성한다.
|
| 28줄F07-L28 | } | Export-Csv -LiteralPath ( |
출고표 28번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 Markdown 표 또는 PowerShell pipeline에서 값을 열이나 다음 명령으로 연결한다.
|
| 29줄F07-L29 | Set-Content -LiteralPath ( |
출고표 29번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W25-D1-prepare.ps1의 다음 검증 또는 설명 단계를 구성한다.
|
| 31줄F07-L31 | $Runner = |
출고표 31번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 32줄F07-L32 | & powershell. |
출고표 32번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W25-D1-prepare.ps1의 다음 검증 또는 설명 단계를 구성한다.
|
| 33줄F07-L33 | -ReferenceRoot $ReferenceRoot -LearnerRoot $LearnerRoot -Week 25 -Phase Prepare -TimeoutSeconds 1200 |
출고표 33번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W25-D1-prepare.ps1의 다음 검증 또는 설명 단계를 구성한다.
|
| 34줄F07-L34 | if ( |
출고표 34번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 native process 종료 코드를 검사해 실패를 놓치지 않는다.
|
| 36줄F07-L36 | $State = |
출고표 36번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 JSON text를 필드로 접근 가능한 PowerShell object로 바꾼다.
|
| 37줄F07-L37 | if ( |
출고표 37번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 조건·반복·함수의 실행 block을 연다.
|
| 38줄F07-L38 | throw 'W25 Prepare state mismatch' |
출고표 38번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 39줄F07-L39 | } |
출고표 39번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 40줄F07-L40 | 'W25_PREPARE_VERIFIED phase= |
출고표 40번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W25-D1-prepare.ps1의 다음 검증 또는 설명 단계를 구성한다.
|
STEP 05 / 13
원본 코드 조각
원본을 4개 의미 조각으로 나누어 그대로 확인합니다.
파일을 한꺼번에 외우지 않고 실행 의미가 이어지는 작은 조각으로 봅니다. 아래 코드는 prompt·fixture·가정을 밝힌 학습용 예시 source이며, 제공 정본 답안이나 실행 결과가 아닌 NOT_RUN 자료입니다.
# W25 PDF p3-p7의 Prepare 흐름을 읽기 좋게 정리한 학습용 예시다.
# packaged reference source가 아니며, Gradle/JUnit Green을 주장하지 않는다.
$ErrorActionPreference = 'Stop'
foreach ($Name in @('FINANCIAL_IT_REFERENCE_ROOT', 'FINANCIAL_IT_LEARNER_ROOT')) {
$Value = [Environment]::GetEnvironmentVariable($Name)
if ([string]::IsNullOrWhiteSpace($Value)) { throw "$Name must be set" }
}
$ReferenceRoot = (Resolve-Path -LiteralPath $env:FINANCIAL_IT_REFERENCE_ROOT).Path
$LearnerRoot = (Resolve-Path -LiteralPath $env:FINANCIAL_IT_LEARNER_ROOT).Path
if ([string]::Equals($ReferenceRoot, $LearnerRoot, [StringComparison]::OrdinalIgnoreCase)) {
throw 'reference and learner roots must be different'
}
$TrackValue = [Environment]::GetEnvironmentVariable('FINANCIAL_IT_SELECTED_TRACK')
$Track = if ([string]::IsNullOrWhiteSpace($TrackValue)) { 'SECURITIES' } else { $TrackValue.ToUpperInvariant() }
if ($Track -cnotin @('SECURITIES', 'CARD')) { throw 'track must be SECURITIES or CARD' }
if ([string]::IsNullOrWhiteSpace($env:FINANCIAL_IT_TRACK_RATIONALE)) {
throw 'FINANCIAL_IT_TRACK_RATIONALE must contain the learner decision'
}
$EvidenceDir = Join-Path $LearnerRoot 'evidence\w25'
New-Item -ItemType Directory -Force -Path $EvidenceDir | Out-Null
[pscustomobject][ordered]@{
selected_track = $Track
decided_at = (Get-Date).ToUniversalTime().ToString('o')
rationale = $env:FINANCIAL_IT_TRACK_RATIONALE
evidence = 'evidence/w25/selection-rationale.txt'
} | Export-Csv -LiteralPath (Join-Path $EvidenceDir 'selected-track.csv') -NoTypeInformation -Encoding utf8
Set-Content -LiteralPath (Join-Path $EvidenceDir 'selection-rationale.txt') -Encoding utf8 -Value $env:FINANCIAL_IT_TRACK_RATIONALE
$Runner = Join-Path $ReferenceRoot 'scripts\apply-track-learning-stage.ps1'
& powershell.exe -NoProfile -ExecutionPolicy Bypass -File $Runner `
-ReferenceRoot $ReferenceRoot -LearnerRoot $LearnerRoot -Week 25 -Phase Prepare -TimeoutSeconds 1200
if ($LASTEXITCODE -ne 0) { throw "W25 Prepare native exit=$LASTEXITCODE" }
$State = Get-Content -Raw -LiteralPath (Join-Path $LearnerRoot '.track-learning-stage.json') | ConvertFrom-Json
if ($State.week -ne 25 -or $State.track -cne $Track -or $State.phase -cne 'Prepared') {
throw 'W25 Prepare state mismatch'
}
'W25_PREPARE_VERIFIED phase=Prepared runtime_claim=false'
STEP 06 / 13
코드 한 줄씩 한국어로 번역
비어 있지 않은 36줄을 모두 한국어로 옮깁니다.
비어 있지 않은 원본 줄은 하나도 생략하지 않습니다.
| 줄 | 원본 | 한국어 번역 |
|---|---|---|
| 1 | # W25 PDF p3-p7의 Prepare 흐름을 읽기 좋게 정리한 학습용 예시다. | 문서 의미: 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다. |
| 2 | # packaged reference source가 아니며, Gradle/JUnit Green을 주장하지 않는다. | 문서 의미: 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다. |
| 3 | $ErrorActionPreference = 'Stop' | 실행 의미: PowerShell 오류를 계속 진행하지 않고 중단시키는 기본 정책을 둔다. |
| 5 | foreach ($Name in @('FINANCIAL_IT_REFERENCE_ROOT', 'FINANCIAL_IT_LEARNER_ROOT')) { | 실행 의미: 고정 목록의 각 항목에 같은 검사를 반복 적용한다. |
| 6 | $Value = [Environment]::GetEnvironmentVariable($Name) | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 7 | if ([string]::IsNullOrWhiteSpace($Value)) { throw "$Name must be set" } | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 8 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 9 | $ReferenceRoot = (Resolve-Path -LiteralPath $env:FINANCIAL_IT_REFERENCE_ROOT).Path | 실행 의미: 입력 경로를 실제 절대 경로로 확인한다. |
| 10 | $LearnerRoot = (Resolve-Path -LiteralPath $env:FINANCIAL_IT_LEARNER_ROOT).Path | 실행 의미: 입력 경로를 실제 절대 경로로 확인한다. |
| 11 | if ([string]::Equals($ReferenceRoot, $LearnerRoot, [StringComparison]::OrdinalIgnoreCase)) { | 실행 의미: 조건·반복·함수의 실행 block을 연다. |
| 12 | throw 'reference and learner roots must be different' | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 13 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 14 | $TrackValue = [Environment]::GetEnvironmentVariable('FINANCIAL_IT_SELECTED_TRACK') | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 15 | $Track = if ([string]::IsNullOrWhiteSpace($TrackValue)) { 'SECURITIES' } else { $TrackValue.ToUpperInvariant() } | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 16 | if ($Track -cnotin @('SECURITIES', 'CARD')) { throw 'track must be SECURITIES or CARD' } | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 17 | if ([string]::IsNullOrWhiteSpace($env:FINANCIAL_IT_TRACK_RATIONALE)) { | 실행 의미: 조건·반복·함수의 실행 block을 연다. |
| 18 | throw 'FINANCIAL_IT_TRACK_RATIONALE must contain the learner decision' | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 19 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 21 | $EvidenceDir = Join-Path $LearnerRoot 'evidence\w25' | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 22 | New-Item -ItemType Directory -Force -Path $EvidenceDir | Out-Null | 실행 의미: Markdown 표 또는 PowerShell pipeline에서 값을 열이나 다음 명령으로 연결한다. |
| 23 | [pscustomobject][ordered]@{ | 실행 의미: 조건·반복·함수의 실행 block을 연다. |
| 24 | selected_track = $Track | 실행 의미: W25-D1-prepare.ps1의 다음 검증 또는 설명 단계를 구성한다. |
| 25 | decided_at = (Get-Date).ToUniversalTime().ToString('o') | 실행 의미: W25-D1-prepare.ps1의 다음 검증 또는 설명 단계를 구성한다. |
| 26 | rationale = $env:FINANCIAL_IT_TRACK_RATIONALE | 실행 의미: W25-D1-prepare.ps1의 다음 검증 또는 설명 단계를 구성한다. |
| 27 | evidence = 'evidence/w25/selection-rationale.txt' | 실행 의미: W25-D1-prepare.ps1의 다음 검증 또는 설명 단계를 구성한다. |
| 28 | } | Export-Csv -LiteralPath (Join-Path $EvidenceDir 'selected-track.csv') -NoTypeInformation -Encoding utf8 | 실행 의미: Markdown 표 또는 PowerShell pipeline에서 값을 열이나 다음 명령으로 연결한다. |
| 29 | Set-Content -LiteralPath (Join-Path $EvidenceDir 'selection-rationale.txt') -Encoding utf8 -Value $env:FINANCIAL_IT_TRACK_RATIONALE | 실행 의미: W25-D1-prepare.ps1의 다음 검증 또는 설명 단계를 구성한다. |
| 31 | $Runner = Join-Path $ReferenceRoot 'scripts\apply-track-learning-stage.ps1' | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 32 | & powershell.exe -NoProfile -ExecutionPolicy Bypass -File $Runner ` | 실행 의미: W25-D1-prepare.ps1의 다음 검증 또는 설명 단계를 구성한다. |
| 33 | -ReferenceRoot $ReferenceRoot -LearnerRoot $LearnerRoot -Week 25 -Phase Prepare -TimeoutSeconds 1200 | 실행 의미: W25-D1-prepare.ps1의 다음 검증 또는 설명 단계를 구성한다. |
| 34 | if ($LASTEXITCODE -ne 0) { throw "W25 Prepare native exit=$LASTEXITCODE" } | 실행 의미: native process 종료 코드를 검사해 실패를 놓치지 않는다. |
| 36 | $State = Get-Content -Raw -LiteralPath (Join-Path $LearnerRoot '.track-learning-stage.json') | ConvertFrom-Json | 실행 의미: JSON text를 필드로 접근 가능한 PowerShell object로 바꾼다. |
| 37 | if ($State.week -ne 25 -or $State.track -cne $Track -or $State.phase -cne 'Prepared') { | 실행 의미: 조건·반복·함수의 실행 block을 연다. |
| 38 | throw 'W25 Prepare state mismatch' | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 39 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 40 | 'W25_PREPARE_VERIFIED phase=Prepared runtime_claim=false' | 실행 의미: W25-D1-prepare.ps1의 다음 검증 또는 설명 단계를 구성한다. |
STEP 07 / 13
기존 수준의 한 줄 읽기·문법 해부
쉬운 설명 다음에 문법과 실행 순서를 정밀하게 읽습니다.
한 줄로 읽기D1 Prepare — 선택 근거와 Prepared state는 FINANCIAL_IT_SELECTED_TRACK이 비어 있으면 SECURITIES를 기본값으로 사용하고 exactly one selected-track.csv를 만든 뒤 Prepare가 test fixture·leak 경계만 검증했는지 확인한다.
문법 해부
- .ps1 문법에서 선언·조건·pipeline·block 경계를 먼저 나눈다.
- manifest의 finalState와 packaged progressive test의 1_000→700/300 oracle을 서로 다른 계약으로 읽는다.
- phase state·native exit·JUnit XML hash·보존된 XML bytes·사람 판정·USER_ATTESTED external status를 서로 대체하지 않는다.
실행 순서
- 기본 트랙은 SECURITIES(증권)이며, 명시적 CARD 선택은 기본값을 덮어쓴다. 실제 실행 전 최종 선택 한 개를 selected-track.csv·근거·state에 같은 값으로 기록하고 서로 다른 reference/learner root를 확인한다.
- Prepare→VerifyStarter→RecordRed→VerifySolution→RecordGreen→Cumulative→Review 순서를 지킨다.
- test를 소유한 세 phase에서만 native exit와 exact JUnit XML 수치를 판정한다.
- 다음 cleanTest 전에 XML bytes를 고유 경로에 보존하고 runtime history hash와 다시 묶는다. Review·Q41·sealed official evidence는 각자의 별도 owner와 검증 수준으로 남긴다.
W25 조각별 정밀 해설
F07-C01 · 원문 1–12줄
- 문법 해부
- .ps1 문법으로 1–12줄의 선언·조건·phase·assert block을 나눈다.
- 실제 값 추적
- default=SECURITIES, SECURITIES xor CARD, selected-track.csv를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- 기본 SECURITIES 또는 명시적으로 덮어쓴 CARD 중 최종 선택 한 개의 selected-track evidence와 runtime 결과에서 expected와 actual이 일치하고 owner evidence가 같은 run/hash 및 보존 XML에 연결되는 경우다. 기본/덮어쓰기 표시만 있고 실행 evidence가 없으면 NOT_RUN이다.
- 틀린 예·반례
- SECURITIES 기본 선택은 runtime 실행 결과가 아니다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- phase 이름·manifest finalState·history hash·exit0 하나를 W25 증거 전체와 같다고 보지 않는다.
- 하지 않는 일
- SECURITIES 기본 선택은 runtime 실행 결과가 아니다; Prepare는 target hash·Gradle·XML·finalState를 검증하지 않는다; reference와 learner root는 서로 달라야 한다; 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다; 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
- 다음 연결
- 다음 조각 또는 F07 evidence 판정으로 상태를 넘긴다.
F07-C02 · 원문 13–24줄
- 문법 해부
- .ps1 문법으로 13–24줄의 선언·조건·phase·assert block을 나눈다.
- 실제 값 추적
- default=SECURITIES, SECURITIES xor CARD, selected-track.csv를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- 기본 SECURITIES 또는 명시적으로 덮어쓴 CARD 중 최종 선택 한 개의 selected-track evidence와 runtime 결과에서 expected와 actual이 일치하고 owner evidence가 같은 run/hash 및 보존 XML에 연결되는 경우다. 기본/덮어쓰기 표시만 있고 실행 evidence가 없으면 NOT_RUN이다.
- 틀린 예·반례
- SECURITIES 기본 선택은 runtime 실행 결과가 아니다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- phase 이름·manifest finalState·history hash·exit0 하나를 W25 증거 전체와 같다고 보지 않는다.
- 하지 않는 일
- SECURITIES 기본 선택은 runtime 실행 결과가 아니다; Prepare는 target hash·Gradle·XML·finalState를 검증하지 않는다; reference와 learner root는 서로 달라야 한다; 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다; 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
- 다음 연결
- 다음 조각 또는 F07 evidence 판정으로 상태를 넘긴다.
F07-C03 · 원문 25–36줄
- 문법 해부
- .ps1 문법으로 25–36줄의 선언·조건·phase·assert block을 나눈다.
- 실제 값 추적
- default=SECURITIES, SECURITIES xor CARD, selected-track.csv를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- 기본 SECURITIES 또는 명시적으로 덮어쓴 CARD 중 최종 선택 한 개의 selected-track evidence와 runtime 결과에서 expected와 actual이 일치하고 owner evidence가 같은 run/hash 및 보존 XML에 연결되는 경우다. 기본/덮어쓰기 표시만 있고 실행 evidence가 없으면 NOT_RUN이다.
- 틀린 예·반례
- SECURITIES 기본 선택은 runtime 실행 결과가 아니다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- phase 이름·manifest finalState·history hash·exit0 하나를 W25 증거 전체와 같다고 보지 않는다.
- 하지 않는 일
- SECURITIES 기본 선택은 runtime 실행 결과가 아니다; Prepare는 target hash·Gradle·XML·finalState를 검증하지 않는다; reference와 learner root는 서로 달라야 한다; 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다; 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
- 다음 연결
- 다음 조각 또는 F07 evidence 판정으로 상태를 넘긴다.
F07-C04 · 원문 37–40줄
- 문법 해부
- .ps1 문법으로 37–40줄의 선언·조건·phase·assert block을 나눈다.
- 실제 값 추적
- default=SECURITIES, SECURITIES xor CARD, selected-track.csv를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- 기본 SECURITIES 또는 명시적으로 덮어쓴 CARD 중 최종 선택 한 개의 selected-track evidence와 runtime 결과에서 expected와 actual이 일치하고 owner evidence가 같은 run/hash 및 보존 XML에 연결되는 경우다. 기본/덮어쓰기 표시만 있고 실행 evidence가 없으면 NOT_RUN이다.
- 틀린 예·반례
- SECURITIES 기본 선택은 runtime 실행 결과가 아니다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- phase 이름·manifest finalState·history hash·exit0 하나를 W25 증거 전체와 같다고 보지 않는다.
- 하지 않는 일
- SECURITIES 기본 선택은 runtime 실행 결과가 아니다; Prepare는 target hash·Gradle·XML·finalState를 검증하지 않는다; reference와 learner root는 서로 달라야 한다; 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다; 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
- 다음 연결
- 다음 조각 또는 F07 evidence 판정으로 상태를 넘긴다.
실행 순서 — D1 Prepare — 선택 근거와 Prepared state
-
SECURITIES xor CARD가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 FINANCIAL_IT_SELECTED_TRACK이 비어 있으면 SECURITIES를 기본값으로 사용하고 exactly one selected-track.csv를 만든 뒤 Prepare가 test fixture·leak 경계만 검증했는지 확인한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘Prepare는 target hash·Gradle·XML·finalState를 검증하지 않는다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 SECURITIES xor CARD와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 08 / 13
실제 값 따라가기
같은 입력값이 어느 줄을 지나 어떤 결과가 되는지 추적합니다.
| 순서 | 들어온 값 | 코드가 하는 일 | 나온 값·상태 | 경계 |
|---|---|---|---|---|
| 입력 | default=SECURITIES | source 계약에 대입 | F07 실행/설명 시작 상태 | SECURITIES 기본 선택은 runtime 실행 결과가 아니다 |
| 검증 | SECURITIES xor CARD | expected와 actual 또는 형식 대조 | 통과 또는 첫 mismatch | Prepare는 target hash·Gradle·XML·finalState를 검증하지 않는다 |
| 증거 | runtime_claim=false | marker·hash·row를 같은 run에 연결 | 범위가 적힌 evidence 후보 | 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다 |
실제 값 — D1 Prepare — 선택 근거와 Prepared state
-
selected-track.csv가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 FINANCIAL_IT_SELECTED_TRACK이 비어 있으면 SECURITIES를 기본값으로 사용하고 exactly one selected-track.csv를 만든 뒤 Prepare가 test fixture·leak 경계만 검증했는지 확인한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘reference와 learner root는 서로 달라야 한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 selected-track.csv와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 09 / 13
Gradle·JUnit XML·PowerShell·SQL 내부에서 벌어지는 일
세 test phase, XML bytes archive, Review, 별도 Q41, USER_ATTESTED sealed 결과의 owner와 증명 범위를 구분합니다.
W25-D1-prepare.ps1 bytes와 track·phase·hash 계약을 읽는다.
SECURITIES 기본 선택과 파일 존재·phase 이름만으로 runtime Green을 주장할 수 없다. 실제 selected-track evidence와 실행 결과는 별도다.RecordRed·RecordGreen·Cumulative에서만 native exit와 exact JUnit XML을 만든다.
SECURITIES 기본 선택은 runtime 실행 결과가 아니다XML bytes를 고유 파일로 보존하고 history hash와 묶은 뒤, Review는 기존 CumulativeGreen만 인용한다. Q41은 별도 PostgreSQL evidence, sealed official status는 user-attested evidence로 남긴다.
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다첫 실패 경계 — D1 Prepare — 선택 근거와 Prepared state
-
Prepared가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 FINANCIAL_IT_SELECTED_TRACK이 비어 있으면 SECURITIES를 기본값으로 사용하고 exactly one selected-track.csv를 만든 뒤 Prepare가 test fixture·leak 경계만 검증했는지 확인한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 Prepared와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 10 / 13
흔한 착각과 틀린 예
그럴듯하지만 틀린 해석을 반례로 고칩니다.
❌ Prepare·VerifyStarter·VerifySolution·Review도 Gradle을 실행해 Green을 만든다.
왜 틀리나 runtime에서 test 실행을 소유하는 phase는 RecordRed·RecordGreen·Cumulative뿐이다.
바르게 읽기 각 phase history의 execution 유무와 mode를 직접 확인한다.
반례 VerifySolution은 solution hash만 검증하므로 새 JUnit XML이 없어야 정상이다.
❌ 기본 트랙이 SECURITIES이므로 CARD도 함께 실행해도 되고, 기본 배지만으로 runtime 선택·실행 증거가 완성된다.
왜 틀리나 W25 계약은 실제 사용자 근거가 있는 선택 트랙 하나와 반대 트랙 leak 부재를 요구한다.
바르게 읽기 기본 선택은 SECURITIES(증권)이며 명시적 CARD 선택은 덮어쓰기다. 실행 전 최종 선택 한 개를 selected-track.csv·근거·state에 같은 값으로 고정한다.
반례 SECURITIES 기본 배지만 보고 test 실행을 주장하거나 두 트랙 test가 함께 보이면 선택 경계를 위반한다.
❌ progressive_contract Green이면 manifest의 finalState 10_000도 증명된다.
왜 틀리나 packaged test는 1_000에서 300을 처리한 700/300만 assert한다.
바르게 읽기 10_000 finalState는 별도 learner test 또는 사람이 결박한 evidence로 증명한다.
반례 runtime은 domainContract.finalState 문자열을 parse하거나 assert하지 않는다.
❌ history에 XML SHA가 있으니 Red·Green·Cumulative XML 원본이 모두 보존됐다.
왜 틀리나 다음 cleanTest가 build/test-results의 이전 XML을 덮어쓰며 state는 bytes를 복사하지 않는다.
바르게 읽기 각 phase 직후 고유 evidence 경로로 원자 복사하고 hash를 history와 대조한다.
반례 RecordGreen 뒤에는 Red XML 경로가 사라질 수 있다.
❌ Review가 새 test를 실행해 CumulativeGreen을 다시 만들고 Q41·sealed official 결과까지 자동 확인한다.
왜 틀리나 Review는 기존 CumulativeGreen을 전제로 review entry와 leak check만 기록한다. Q41은 별도 PostgreSQL 과제이고 sealed official status는 user-attested다.
바르게 읽기 Review에서는 reviewedPhase와 history 증가만 보고, Q41 native evidence와 USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED sealed evidence를 별도로 판정한다.
반례 Review 뒤 phase는 여전히 CumulativeGreen이고 새 execution/XML·Q41 transcript·official login verification이 생기지 않는다.
STEP 11 / 13
이 코드가 보장하지 않는 것
선택 미결정·10_000 finalState·XML 보존·Review/Q41/sealed official truth처럼 이 코드가 책임지지 않는 일을 분리합니다.
SECURITIES 기본 선택은 runtime 실행 결과가 아니다
이 책임을 맡는 곳: runtime GatePrepare는 target hash·Gradle·XML·finalState를 검증하지 않는다
이 책임을 맡는 곳: external/human reviewreference와 learner root는 서로 달라야 한다
이 책임을 맡는 곳: release manifest기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
이 책임을 맡는 곳: 운영 환경증명하지 않는 범위 — D1 Prepare — 선택 근거와 Prepared state
-
runtime_claim=false가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 FINANCIAL_IT_SELECTED_TRACK이 비어 있으면 SECURITIES를 기본값으로 사용하고 exactly one selected-track.csv를 만든 뒤 Prepare가 test fixture·leak 경계만 검증했는지 확인한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 runtime_claim=false와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 12 / 13
직접 다시 써보기
뜻 → 조각 → 전체 코드 순서로 다시 씁니다.
1단계 · 뜻부터 복원
- FINANCIAL_IT_SELECTED_TRACK이 비어 있으면 SECURITIES를 기본값으로 사용하고 exactly one selected-track.csv를 만든 뒤 Prepare가 test fixture·leak 경계만 검증했는지 확인한다.
- 핵심 값은 default=SECURITIES, SECURITIES xor CARD, selected-track.csv, Prepared, runtime_claim=false다.
2단계 · 코드 조각 재조립
- 1. 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다
- 2. 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다
- 3. PowerShell 오류를 계속 진행하지 않고 중단시키는 기본 정책을 둔다
- 5. 고정 목록의 각 항목에 같은 검사를 반복 적용한다
- 6. 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다
- 7. 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다
- 8. 앞에서 연 block 또는 호출 범위를 닫는다
- 9. 입력 경로를 실제 절대 경로로 확인한다
3단계 · 파일 전체 다시 쓰기
illustrative/powershell/W25-D1-prepare.ps1을 새 파일에 다시 쓰고 expected·actual·실패·cleanup·비범위를 주석으로 표시한다.
자가 점검
- 비어 있지 않은 모든 source 줄을 한 번씩 읽었나?
- 기본 트랙을 SECURITIES(증권) 하나로 두고 기본 선택·selected-track evidence·runtime Green을 서로 분리했나?
- Review·Q41·USER_ATTESTED sealed 상태를 자동 성공으로 꾸미지 않았나?
- XML bytes archive와 첫 실패·cleanup 책임을 설명할 수 있나?
STEP 13 / 13
전체 원본 source
감사로 고정한 전체 source를 가감 없이 확인합니다.
학습용 예시 전체 확인하기 · 정본 답안 아님 · NOT_RUN
# W25 PDF p3-p7의 Prepare 흐름을 읽기 좋게 정리한 학습용 예시다.
# packaged reference source가 아니며, Gradle/JUnit Green을 주장하지 않는다.
$ErrorActionPreference = 'Stop'
foreach ($Name in @('FINANCIAL_IT_REFERENCE_ROOT', 'FINANCIAL_IT_LEARNER_ROOT')) {
$Value = [Environment]::GetEnvironmentVariable($Name)
if ([string]::IsNullOrWhiteSpace($Value)) { throw "$Name must be set" }
}
$ReferenceRoot = (Resolve-Path -LiteralPath $env:FINANCIAL_IT_REFERENCE_ROOT).Path
$LearnerRoot = (Resolve-Path -LiteralPath $env:FINANCIAL_IT_LEARNER_ROOT).Path
if ([string]::Equals($ReferenceRoot, $LearnerRoot, [StringComparison]::OrdinalIgnoreCase)) {
throw 'reference and learner roots must be different'
}
$TrackValue = [Environment]::GetEnvironmentVariable('FINANCIAL_IT_SELECTED_TRACK')
$Track = if ([string]::IsNullOrWhiteSpace($TrackValue)) { 'SECURITIES' } else { $TrackValue.ToUpperInvariant() }
if ($Track -cnotin @('SECURITIES', 'CARD')) { throw 'track must be SECURITIES or CARD' }
if ([string]::IsNullOrWhiteSpace($env:FINANCIAL_IT_TRACK_RATIONALE)) {
throw 'FINANCIAL_IT_TRACK_RATIONALE must contain the learner decision'
}
$EvidenceDir = Join-Path $LearnerRoot 'evidence\w25'
New-Item -ItemType Directory -Force -Path $EvidenceDir | Out-Null
[pscustomobject][ordered]@{
selected_track = $Track
decided_at = (Get-Date).ToUniversalTime().ToString('o')
rationale = $env:FINANCIAL_IT_TRACK_RATIONALE
evidence = 'evidence/w25/selection-rationale.txt'
} | Export-Csv -LiteralPath (Join-Path $EvidenceDir 'selected-track.csv') -NoTypeInformation -Encoding utf8
Set-Content -LiteralPath (Join-Path $EvidenceDir 'selection-rationale.txt') -Encoding utf8 -Value $env:FINANCIAL_IT_TRACK_RATIONALE
$Runner = Join-Path $ReferenceRoot 'scripts\apply-track-learning-stage.ps1'
& powershell.exe -NoProfile -ExecutionPolicy Bypass -File $Runner `
-ReferenceRoot $ReferenceRoot -LearnerRoot $LearnerRoot -Week 25 -Phase Prepare -TimeoutSeconds 1200
if ($LASTEXITCODE -ne 0) { throw "W25 Prepare native exit=$LASTEXITCODE" }
$State = Get-Content -Raw -LiteralPath (Join-Path $LearnerRoot '.track-learning-stage.json') | ConvertFrom-Json
if ($State.week -ne 25 -or $State.track -cne $Track -or $State.phase -cne 'Prepared') {
throw 'W25 Prepare state mismatch'
}
'W25_PREPARE_VERIFIED phase=Prepared runtime_claim=false'
08SECURITIES starter CashWallet — available 차감 누락
track_learning_stages/securities/w25/starter/src/main/java/com/example/financialcore/securities/CashWallet.java
PDF 전문 정본 · learner starter Java · 정본 · W25-F0856줄 연결56줄 번역6 chunks
SECURITIES starter CashWallet — available 차감 누락
track_learning_stages/securities/w25/starter/src/main/java/com/example/financialcore/securities/CashWallet.java
PDF 전문 정본 · learner starter Java · 정본 · W25-F08STEP 01 / 13
오늘 이 코드에서 해결할 문제
무엇을 이해해야 하는지 질문부터 잡습니다.
reserve가 reserved만 늘려 같은 현금을 다시 예약할 수 있는 의도한 Red 반례를 읽는다.
- availableCash=1_000은 어느 source와 실제 결과에서 확인해야 할까?
- 첫 실패를 만드는 조건과 fail-closed 지점은 어디일까?
- 왜 ‘reference asset을 복사했다고 learner authorship이 되지 않는다’를 별도 경계로 남겨야 할까?
availableCash=1_000reservedCash=0reserve(300)available remains 1_000RED comment왜 필요한가 — SECURITIES starter CashWallet — available 차감 누락
-
availableCash=1_000가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 reserve가 reserved만 늘려 같은 현금을 다시 예약할 수 있는 의도한 Red 반례를 읽는다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘reference asset을 복사했다고 learner authorship이 되지 않는다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 availableCash=1_000와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 02 / 13
아주 짧게: 이 코드는 왜 필요할까?
웹소설 대신 이 코드가 필요한 이유만 두 문단으로 쉽게 봅니다.
사용자의 기본 선택에 따라 이 HTML은 SECURITIES(증권)을 주 트랙으로 읽는다. CARD는 비교용이며 명시적으로 고르면 기본값을 덮어쓸 수 있다. 실제 실행은 최종 선택 한 개를 selected-track.csv·근거·state에 같은 값으로 기록하고 reference와 learner 폴더를 분리한 뒤에만 시작한다. 이 HTML 자체는 Gradle/JUnit을 실행하지 않아 NOT_RUN 상태다.
한 통장만 골라 빨강에서 초록까지 증명하는 일주일
이 파일은 reserve가 reserved만 늘려 같은 현금을 다시 예약할 수 있는 의도한 Red 반례를 읽는다. 눈으로 읽을 때는 각 줄을 검수표 한 칸처럼 보고, 입력과 다음 상태를 놓치지 않는다.
마지막 도장은 hash 확인, 세 test phase의 실제 JUnit 실행, XML bytes archive, 사람 review를 서로 구분한 뒤에만 찍는다. Review는 새 test가 아니며 Q41은 stage runtime 밖의 별도 NOT_RUN 과제, sealed official status는 USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED다. 특히 reference asset을 복사했다고 learner authorship이 되지 않는다
딱 여기까지만 비유와 SECURITIES 기본 배지는 실제 selected-track 근거, Gradle/JUnit 실행, XML bytes 보존, 사람 review, Q41 실행, sealed official 확인을 대신하지 않는다.
STEP 03 / 13
초등학생도 이해하는 설명
생활 비유와 실제 코드의 경계를 함께 확인합니다.
값 1: availableCash=1_000
이 파일에서 계속 확인할 고정 단서가 availableCash=1_000다.
- 코드 연결
F08 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- reference asset을 복사했다고 learner authorship이 되지 않는다
값 2: reservedCash=0
이 파일에서 계속 확인할 고정 단서가 reservedCash=0다.
- 코드 연결
F08 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- UTF-8 BOM은 runtime이 거절한다
값 3: reserve(300)
이 파일에서 계속 확인할 고정 단서가 reserve(300)다.
- 코드 연결
F08 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- 선택하지 않은 트랙은 N-A_UNSELECTED
값 4: available remains 1_000
이 파일에서 계속 확인할 고정 단서가 available remains 1_000다.
- 코드 연결
F08 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- reference와 learner root는 서로 달라야 한다
값 5: RED comment
이 파일에서 계속 확인할 고정 단서가 RED comment다.
- 코드 연결
F08 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
STEP 04 / 13
비유 ↔ 코드 전체 연결표
감사 규칙상 연결 대상인 원본 56줄을 빠짐없이 연결합니다.
| 줄 | 정확한 원본 줄 | STARRY 비유 | 실제 뜻·입력·결과·한계 |
|---|---|---|---|
| 1줄F08-L01 | package com. |
출고표 1번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 3줄F08-L03 | import jakarta. |
출고표 3번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 4줄F08-L04 | import jakarta. |
출고표 4번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 5줄F08-L05 | import jakarta. |
출고표 5번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 6줄F08-L06 | import jakarta. |
출고표 6번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 7줄F08-L07 | import jakarta. |
출고표 7번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 8줄F08-L08 | import jakarta. |
출고표 8번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 9줄F08-L09 | import jakarta. |
출고표 9번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 11줄F08-L11 | @Entity |
출고표 11번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 12줄F08-L12 | @Table( |
출고표 12번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 13줄F08-L13 | public class CashWallet { |
출고표 13번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 조건·반복·함수의 실행 block을 연다.
|
| 14줄F08-L14 | @Id |
출고표 14번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 15줄F08-L15 | @GeneratedValue( |
출고표 15번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 16줄F08-L16 | private Long id; |
출고표 16번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 18줄F08-L18 | @Column( |
출고표 18번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 19줄F08-L19 | private String investorKey; |
출고표 19번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 21줄F08-L21 | @Column( |
출고표 21번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 22줄F08-L22 | private long availableCash; |
출고표 22번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 24줄F08-L24 | @Column( |
출고표 24번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 25줄F08-L25 | private long reservedCash; |
출고표 25번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 27줄F08-L27 | @Version |
출고표 27번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 28줄F08-L28 | private long version; |
출고표 28번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 30줄F08-L30 | protected CashWallet( |
출고표 30번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 32줄F08-L32 | private CashWallet( |
출고표 32번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 조건·반복·함수의 실행 block을 연다.
|
| 33줄F08-L33 | if ( |
출고표 33번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 34줄F08-L34 | if ( |
출고표 34번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 35줄F08-L35 | this. |
출고표 35번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 36줄F08-L36 | this. |
출고표 36번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 37줄F08-L37 | } |
출고표 37번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 39줄F08-L39 | public static CashWallet open( |
출고표 39번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 조건·반복·함수의 실행 block을 연다.
|
| 40줄F08-L40 | return new CashWallet( |
출고표 40번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 41줄F08-L41 | } |
출고표 41번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 43줄F08-L43 | public void reserve( |
출고표 43번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 조건·반복·함수의 실행 block을 연다.
|
| 44줄F08-L44 | if ( |
출고표 44번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 45줄F08-L45 | if ( |
출고표 45번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 46줄F08-L46 | / |
출고표 46번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 47줄F08-L47 | reservedCash = |
출고표 47번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 48줄F08-L48 | } |
출고표 48번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 50줄F08-L50 | public void settle( |
출고표 50번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 조건·반복·함수의 실행 block을 연다.
|
| 51줄F08-L51 | if ( |
출고표 51번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 Markdown 표 또는 PowerShell pipeline에서 값을 열이나 다음 명령으로 연결한다.
|
| 52줄F08-L52 | throw new IllegalArgumentException( |
출고표 52번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 53줄F08-L53 | } |
출고표 53번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 54줄F08-L54 | if ( |
출고표 54번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 55줄F08-L55 | reservedCash -= |
출고표 55번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 56줄F08-L56 | availableCash = |
출고표 56번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 57줄F08-L57 | } |
출고표 57번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 59줄F08-L59 | public void releaseReservation( |
출고표 59번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 조건·반복·함수의 실행 block을 연다.
|
| 60줄F08-L60 | if ( |
출고표 60번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 61줄F08-L61 | reservedCash -= |
출고표 61번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 62줄F08-L62 | availableCash = |
출고표 62번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 63줄F08-L63 | } |
출고표 63번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 65줄F08-L65 | public Long getId( |
출고표 65번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 66줄F08-L66 | public String getInvestorKey( |
출고표 66번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 67줄F08-L67 | public long getAvailableCash( |
출고표 67번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 예약 뒤 가용 현금이 700인지 관찰한다.
|
| 68줄F08-L68 | public long getReservedCash( |
출고표 68번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 예약 뒤 예약 현금이 300인지 관찰한다.
|
| 69줄F08-L69 | } |
출고표 69번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
STEP 05 / 13
원본 코드 조각
원본을 6개 의미 조각으로 나누어 그대로 확인합니다.
파일을 한꺼번에 외우지 않고 실행 의미가 이어지는 작은 조각으로 봅니다. 아래 코드는 hash로 고정한 native 정본 source에서 그대로 잘랐습니다.
package com.example.financialcore.securities;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import jakarta.persistence.Version;
@Entity
@Table(name = "securities_cash_wallet")
public class CashWallet {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "investor_key", nullable = false, unique = true, length = 64)
private String investorKey;
@Column(name = "available_cash", nullable = false)
private long availableCash;
@Column(name = "reserved_cash", nullable = false)
private long reservedCash;
@Version
private long version;
protected CashWallet() {}
private CashWallet(String investorKey, long availableCash) {
if (investorKey == null || investorKey.isBlank()) throw new IllegalArgumentException("investorKey");
if (availableCash < 0) throw new IllegalArgumentException("availableCash");
this.investorKey = investorKey;
this.availableCash = availableCash;
}
public static CashWallet open(String investorKey, long availableCash) {
return new CashWallet(investorKey, availableCash);
}
public void reserve(long amount) {
if (amount <= 0) throw new IllegalArgumentException("amount");
if (availableCash < amount) throw new IllegalStateException("INSUFFICIENT_AVAILABLE_CASH");
// RED: available cash is not reduced
reservedCash = Math.addExact(reservedCash, amount);
}
public void settle(long reservedAmount, long executedAmount) {
if (reservedAmount <= 0 || executedAmount <= 0 || executedAmount > reservedAmount) {
throw new IllegalArgumentException("settlement amount");
}
if (reservedCash < reservedAmount) throw new IllegalStateException("RESERVATION_MISMATCH");
reservedCash -= reservedAmount;
availableCash = Math.addExact(availableCash, reservedAmount - executedAmount);
}
public void releaseReservation(long amount) {
if (amount <= 0 || reservedCash < amount) throw new IllegalArgumentException("amount");
reservedCash -= amount;
availableCash = Math.addExact(availableCash, amount);
}
public Long getId() { return id; }
public String getInvestorKey() { return investorKey; }
public long getAvailableCash() { return availableCash; }
public long getReservedCash() { return reservedCash; }
}
STEP 06 / 13
코드 한 줄씩 한국어로 번역
비어 있지 않은 56줄을 모두 한국어로 옮깁니다.
비어 있지 않은 원본 줄은 하나도 생략하지 않습니다.
| 줄 | 원본 | 한국어 번역 |
|---|---|---|
| 1 | package com.example.financialcore.securities; | 실행 의미: CashWallet.java의 다음 검증 또는 설명 단계를 구성한다. |
| 3 | import jakarta.persistence.Column; | 실행 의미: CashWallet.java의 다음 검증 또는 설명 단계를 구성한다. |
| 4 | import jakarta.persistence.Entity; | 실행 의미: CashWallet.java의 다음 검증 또는 설명 단계를 구성한다. |
| 5 | import jakarta.persistence.GeneratedValue; | 실행 의미: CashWallet.java의 다음 검증 또는 설명 단계를 구성한다. |
| 6 | import jakarta.persistence.GenerationType; | 실행 의미: CashWallet.java의 다음 검증 또는 설명 단계를 구성한다. |
| 7 | import jakarta.persistence.Id; | 실행 의미: CashWallet.java의 다음 검증 또는 설명 단계를 구성한다. |
| 8 | import jakarta.persistence.Table; | 실행 의미: CashWallet.java의 다음 검증 또는 설명 단계를 구성한다. |
| 9 | import jakarta.persistence.Version; | 실행 의미: CashWallet.java의 다음 검증 또는 설명 단계를 구성한다. |
| 11 | @Entity | 실행 의미: CashWallet.java의 다음 검증 또는 설명 단계를 구성한다. |
| 12 | @Table(name = "securities_cash_wallet") | 실행 의미: CashWallet.java의 다음 검증 또는 설명 단계를 구성한다. |
| 13 | public class CashWallet { | 실행 의미: 조건·반복·함수의 실행 block을 연다. |
| 14 | @Id | 실행 의미: CashWallet.java의 다음 검증 또는 설명 단계를 구성한다. |
| 15 | @GeneratedValue(strategy = GenerationType.IDENTITY) | 실행 의미: CashWallet.java의 다음 검증 또는 설명 단계를 구성한다. |
| 16 | private Long id; | 실행 의미: CashWallet.java의 다음 검증 또는 설명 단계를 구성한다. |
| 18 | @Column(name = "investor_key", nullable = false, unique = true, length = 64) | 실행 의미: CashWallet.java의 다음 검증 또는 설명 단계를 구성한다. |
| 19 | private String investorKey; | 실행 의미: CashWallet.java의 다음 검증 또는 설명 단계를 구성한다. |
| 21 | @Column(name = "available_cash", nullable = false) | 실행 의미: CashWallet.java의 다음 검증 또는 설명 단계를 구성한다. |
| 22 | private long availableCash; | 실행 의미: CashWallet.java의 다음 검증 또는 설명 단계를 구성한다. |
| 24 | @Column(name = "reserved_cash", nullable = false) | 실행 의미: CashWallet.java의 다음 검증 또는 설명 단계를 구성한다. |
| 25 | private long reservedCash; | 실행 의미: CashWallet.java의 다음 검증 또는 설명 단계를 구성한다. |
| 27 | @Version | 실행 의미: CashWallet.java의 다음 검증 또는 설명 단계를 구성한다. |
| 28 | private long version; | 실행 의미: CashWallet.java의 다음 검증 또는 설명 단계를 구성한다. |
| 30 | protected CashWallet() {} | 실행 의미: CashWallet.java의 다음 검증 또는 설명 단계를 구성한다. |
| 32 | private CashWallet(String investorKey, long availableCash) { | 실행 의미: 조건·반복·함수의 실행 block을 연다. |
| 33 | if (investorKey == null || investorKey.isBlank()) throw new IllegalArgumentException("investorKey"); | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 34 | if (availableCash < 0) throw new IllegalArgumentException("availableCash"); | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 35 | this.investorKey = investorKey; | 실행 의미: CashWallet.java의 다음 검증 또는 설명 단계를 구성한다. |
| 36 | this.availableCash = availableCash; | 실행 의미: CashWallet.java의 다음 검증 또는 설명 단계를 구성한다. |
| 37 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 39 | public static CashWallet open(String investorKey, long availableCash) { | 실행 의미: 조건·반복·함수의 실행 block을 연다. |
| 40 | return new CashWallet(investorKey, availableCash); | 실행 의미: CashWallet.java의 다음 검증 또는 설명 단계를 구성한다. |
| 41 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 43 | public void reserve(long amount) { | 실행 의미: 조건·반복·함수의 실행 block을 연다. |
| 44 | if (amount <= 0) throw new IllegalArgumentException("amount"); | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 45 | if (availableCash < amount) throw new IllegalStateException("INSUFFICIENT_AVAILABLE_CASH"); | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 46 | // RED: available cash is not reduced | 실행 의미: CashWallet.java의 다음 검증 또는 설명 단계를 구성한다. |
| 47 | reservedCash = Math.addExact(reservedCash, amount); | 실행 의미: CashWallet.java의 다음 검증 또는 설명 단계를 구성한다. |
| 48 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 50 | public void settle(long reservedAmount, long executedAmount) { | 실행 의미: 조건·반복·함수의 실행 block을 연다. |
| 51 | if (reservedAmount <= 0 || executedAmount <= 0 || executedAmount > reservedAmount) { | 실행 의미: Markdown 표 또는 PowerShell pipeline에서 값을 열이나 다음 명령으로 연결한다. |
| 52 | throw new IllegalArgumentException("settlement amount"); | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 53 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 54 | if (reservedCash < reservedAmount) throw new IllegalStateException("RESERVATION_MISMATCH"); | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 55 | reservedCash -= reservedAmount; | 실행 의미: CashWallet.java의 다음 검증 또는 설명 단계를 구성한다. |
| 56 | availableCash = Math.addExact(availableCash, reservedAmount - executedAmount); | 실행 의미: CashWallet.java의 다음 검증 또는 설명 단계를 구성한다. |
| 57 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 59 | public void releaseReservation(long amount) { | 실행 의미: 조건·반복·함수의 실행 block을 연다. |
| 60 | if (amount <= 0 || reservedCash < amount) throw new IllegalArgumentException("amount"); | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 61 | reservedCash -= amount; | 실행 의미: CashWallet.java의 다음 검증 또는 설명 단계를 구성한다. |
| 62 | availableCash = Math.addExact(availableCash, amount); | 실행 의미: CashWallet.java의 다음 검증 또는 설명 단계를 구성한다. |
| 63 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 65 | public Long getId() { return id; } | 실행 의미: CashWallet.java의 다음 검증 또는 설명 단계를 구성한다. |
| 66 | public String getInvestorKey() { return investorKey; } | 실행 의미: CashWallet.java의 다음 검증 또는 설명 단계를 구성한다. |
| 67 | public long getAvailableCash() { return availableCash; } | 실행 의미: 예약 뒤 가용 현금이 700인지 관찰한다. |
| 68 | public long getReservedCash() { return reservedCash; } | 실행 의미: 예약 뒤 예약 현금이 300인지 관찰한다. |
| 69 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
STEP 07 / 13
기존 수준의 한 줄 읽기·문법 해부
쉬운 설명 다음에 문법과 실행 순서를 정밀하게 읽습니다.
한 줄로 읽기SECURITIES starter CashWallet — available 차감 누락는 reserve가 reserved만 늘려 같은 현금을 다시 예약할 수 있는 의도한 Red 반례를 읽는다.
문법 해부
- .java 문법에서 선언·조건·pipeline·block 경계를 먼저 나눈다.
- manifest의 finalState와 packaged progressive test의 1_000→700/300 oracle을 서로 다른 계약으로 읽는다.
- phase state·native exit·JUnit XML hash·보존된 XML bytes·사람 판정·USER_ATTESTED external status를 서로 대체하지 않는다.
실행 순서
- 기본 트랙은 SECURITIES(증권)이며, 명시적 CARD 선택은 기본값을 덮어쓴다. 실제 실행 전 최종 선택 한 개를 selected-track.csv·근거·state에 같은 값으로 기록하고 서로 다른 reference/learner root를 확인한다.
- Prepare→VerifyStarter→RecordRed→VerifySolution→RecordGreen→Cumulative→Review 순서를 지킨다.
- test를 소유한 세 phase에서만 native exit와 exact JUnit XML 수치를 판정한다.
- 다음 cleanTest 전에 XML bytes를 고유 경로에 보존하고 runtime history hash와 다시 묶는다. Review·Q41·sealed official evidence는 각자의 별도 owner와 검증 수준으로 남긴다.
W25 조각별 정밀 해설
F08-C01 · 원문 1–12줄
- 문법 해부
- .java 문법으로 1–12줄의 선언·조건·phase·assert block을 나눈다.
- 실제 값 추적
- availableCash=1_000, reservedCash=0, reserve(300)를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- 기본 SECURITIES 또는 명시적으로 덮어쓴 CARD 중 최종 선택 한 개의 selected-track evidence와 runtime 결과에서 expected와 actual이 일치하고 owner evidence가 같은 run/hash 및 보존 XML에 연결되는 경우다. 기본/덮어쓰기 표시만 있고 실행 evidence가 없으면 NOT_RUN이다.
- 틀린 예·반례
- reference asset을 복사했다고 learner authorship이 되지 않는다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- phase 이름·manifest finalState·history hash·exit0 하나를 W25 증거 전체와 같다고 보지 않는다.
- 하지 않는 일
- reference asset을 복사했다고 learner authorship이 되지 않는다; UTF-8 BOM은 runtime이 거절한다; 선택하지 않은 트랙은 N-A_UNSELECTED; reference와 learner root는 서로 달라야 한다; 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다; 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
- 다음 연결
- 다음 조각 또는 F08 evidence 판정으로 상태를 넘긴다.
F08-C02 · 원문 13–24줄
- 문법 해부
- .java 문법으로 13–24줄의 선언·조건·phase·assert block을 나눈다.
- 실제 값 추적
- availableCash=1_000, reservedCash=0, reserve(300)를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- 기본 SECURITIES 또는 명시적으로 덮어쓴 CARD 중 최종 선택 한 개의 selected-track evidence와 runtime 결과에서 expected와 actual이 일치하고 owner evidence가 같은 run/hash 및 보존 XML에 연결되는 경우다. 기본/덮어쓰기 표시만 있고 실행 evidence가 없으면 NOT_RUN이다.
- 틀린 예·반례
- reference asset을 복사했다고 learner authorship이 되지 않는다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- phase 이름·manifest finalState·history hash·exit0 하나를 W25 증거 전체와 같다고 보지 않는다.
- 하지 않는 일
- reference asset을 복사했다고 learner authorship이 되지 않는다; UTF-8 BOM은 runtime이 거절한다; 선택하지 않은 트랙은 N-A_UNSELECTED; reference와 learner root는 서로 달라야 한다; 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다; 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
- 다음 연결
- 다음 조각 또는 F08 evidence 판정으로 상태를 넘긴다.
F08-C03 · 원문 25–36줄
- 문법 해부
- .java 문법으로 25–36줄의 선언·조건·phase·assert block을 나눈다.
- 실제 값 추적
- availableCash=1_000, reservedCash=0, reserve(300)를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- 기본 SECURITIES 또는 명시적으로 덮어쓴 CARD 중 최종 선택 한 개의 selected-track evidence와 runtime 결과에서 expected와 actual이 일치하고 owner evidence가 같은 run/hash 및 보존 XML에 연결되는 경우다. 기본/덮어쓰기 표시만 있고 실행 evidence가 없으면 NOT_RUN이다.
- 틀린 예·반례
- reference asset을 복사했다고 learner authorship이 되지 않는다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- phase 이름·manifest finalState·history hash·exit0 하나를 W25 증거 전체와 같다고 보지 않는다.
- 하지 않는 일
- reference asset을 복사했다고 learner authorship이 되지 않는다; UTF-8 BOM은 runtime이 거절한다; 선택하지 않은 트랙은 N-A_UNSELECTED; reference와 learner root는 서로 달라야 한다; 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다; 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
- 다음 연결
- 다음 조각 또는 F08 evidence 판정으로 상태를 넘긴다.
F08-C04 · 원문 37–48줄
- 문법 해부
- .java 문법으로 37–48줄의 선언·조건·phase·assert block을 나눈다.
- 실제 값 추적
- availableCash=1_000, reservedCash=0, reserve(300)를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- 기본 SECURITIES 또는 명시적으로 덮어쓴 CARD 중 최종 선택 한 개의 selected-track evidence와 runtime 결과에서 expected와 actual이 일치하고 owner evidence가 같은 run/hash 및 보존 XML에 연결되는 경우다. 기본/덮어쓰기 표시만 있고 실행 evidence가 없으면 NOT_RUN이다.
- 틀린 예·반례
- reference asset을 복사했다고 learner authorship이 되지 않는다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- phase 이름·manifest finalState·history hash·exit0 하나를 W25 증거 전체와 같다고 보지 않는다.
- 하지 않는 일
- reference asset을 복사했다고 learner authorship이 되지 않는다; UTF-8 BOM은 runtime이 거절한다; 선택하지 않은 트랙은 N-A_UNSELECTED; reference와 learner root는 서로 달라야 한다; 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다; 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
- 다음 연결
- 다음 조각 또는 F08 evidence 판정으로 상태를 넘긴다.
F08-C05 · 원문 49–60줄
- 문법 해부
- .java 문법으로 49–60줄의 선언·조건·phase·assert block을 나눈다.
- 실제 값 추적
- availableCash=1_000, reservedCash=0, reserve(300)를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- 기본 SECURITIES 또는 명시적으로 덮어쓴 CARD 중 최종 선택 한 개의 selected-track evidence와 runtime 결과에서 expected와 actual이 일치하고 owner evidence가 같은 run/hash 및 보존 XML에 연결되는 경우다. 기본/덮어쓰기 표시만 있고 실행 evidence가 없으면 NOT_RUN이다.
- 틀린 예·반례
- reference asset을 복사했다고 learner authorship이 되지 않는다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- phase 이름·manifest finalState·history hash·exit0 하나를 W25 증거 전체와 같다고 보지 않는다.
- 하지 않는 일
- reference asset을 복사했다고 learner authorship이 되지 않는다; UTF-8 BOM은 runtime이 거절한다; 선택하지 않은 트랙은 N-A_UNSELECTED; reference와 learner root는 서로 달라야 한다; 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다; 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
- 다음 연결
- 다음 조각 또는 F08 evidence 판정으로 상태를 넘긴다.
F08-C06 · 원문 61–69줄
- 문법 해부
- .java 문법으로 61–69줄의 선언·조건·phase·assert block을 나눈다.
- 실제 값 추적
- availableCash=1_000, reservedCash=0, reserve(300)를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- 기본 SECURITIES 또는 명시적으로 덮어쓴 CARD 중 최종 선택 한 개의 selected-track evidence와 runtime 결과에서 expected와 actual이 일치하고 owner evidence가 같은 run/hash 및 보존 XML에 연결되는 경우다. 기본/덮어쓰기 표시만 있고 실행 evidence가 없으면 NOT_RUN이다.
- 틀린 예·반례
- reference asset을 복사했다고 learner authorship이 되지 않는다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- phase 이름·manifest finalState·history hash·exit0 하나를 W25 증거 전체와 같다고 보지 않는다.
- 하지 않는 일
- reference asset을 복사했다고 learner authorship이 되지 않는다; UTF-8 BOM은 runtime이 거절한다; 선택하지 않은 트랙은 N-A_UNSELECTED; reference와 learner root는 서로 달라야 한다; 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다; 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
- 다음 연결
- 다음 조각 또는 F08 evidence 판정으로 상태를 넘긴다.
실행 순서 — SECURITIES starter CashWallet — available 차감 누락
-
reservedCash=0가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 reserve가 reserved만 늘려 같은 현금을 다시 예약할 수 있는 의도한 Red 반례를 읽는다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘UTF-8 BOM은 runtime이 거절한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 reservedCash=0와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 08 / 13
실제 값 따라가기
같은 입력값이 어느 줄을 지나 어떤 결과가 되는지 추적합니다.
| 순서 | 들어온 값 | 코드가 하는 일 | 나온 값·상태 | 경계 |
|---|---|---|---|---|
| 입력 | availableCash=1_000 | source 계약에 대입 | F08 실행/설명 시작 상태 | reference asset을 복사했다고 learner authorship이 되지 않는다 |
| 검증 | reservedCash=0 | expected와 actual 또는 형식 대조 | 통과 또는 첫 mismatch | UTF-8 BOM은 runtime이 거절한다 |
| 증거 | RED comment | marker·hash·row를 같은 run에 연결 | 범위가 적힌 evidence 후보 | 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다 |
실제 값 — SECURITIES starter CashWallet — available 차감 누락
-
reserve(300)가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 reserve가 reserved만 늘려 같은 현금을 다시 예약할 수 있는 의도한 Red 반례를 읽는다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘선택하지 않은 트랙은 N-A_UNSELECTED’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 reserve(300)와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 09 / 13
Gradle·JUnit XML·PowerShell·SQL 내부에서 벌어지는 일
세 test phase, XML bytes archive, Review, 별도 Q41, USER_ATTESTED sealed 결과의 owner와 증명 범위를 구분합니다.
CashWallet.java bytes와 track·phase·hash 계약을 읽는다.
SECURITIES 기본 선택과 파일 존재·phase 이름만으로 runtime Green을 주장할 수 없다. 실제 selected-track evidence와 실행 결과는 별도다.RecordRed·RecordGreen·Cumulative에서만 native exit와 exact JUnit XML을 만든다.
reference asset을 복사했다고 learner authorship이 되지 않는다XML bytes를 고유 파일로 보존하고 history hash와 묶은 뒤, Review는 기존 CumulativeGreen만 인용한다. Q41은 별도 PostgreSQL evidence, sealed official status는 user-attested evidence로 남긴다.
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다첫 실패 경계 — SECURITIES starter CashWallet — available 차감 누락
-
available remains 1_000가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 reserve가 reserved만 늘려 같은 현금을 다시 예약할 수 있는 의도한 Red 반례를 읽는다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘reference와 learner root는 서로 달라야 한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 available remains 1_000와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 10 / 13
흔한 착각과 틀린 예
그럴듯하지만 틀린 해석을 반례로 고칩니다.
❌ Prepare·VerifyStarter·VerifySolution·Review도 Gradle을 실행해 Green을 만든다.
왜 틀리나 runtime에서 test 실행을 소유하는 phase는 RecordRed·RecordGreen·Cumulative뿐이다.
바르게 읽기 각 phase history의 execution 유무와 mode를 직접 확인한다.
반례 VerifySolution은 solution hash만 검증하므로 새 JUnit XML이 없어야 정상이다.
❌ 기본 트랙이 SECURITIES이므로 CARD도 함께 실행해도 되고, 기본 배지만으로 runtime 선택·실행 증거가 완성된다.
왜 틀리나 W25 계약은 실제 사용자 근거가 있는 선택 트랙 하나와 반대 트랙 leak 부재를 요구한다.
바르게 읽기 기본 선택은 SECURITIES(증권)이며 명시적 CARD 선택은 덮어쓰기다. 실행 전 최종 선택 한 개를 selected-track.csv·근거·state에 같은 값으로 고정한다.
반례 SECURITIES 기본 배지만 보고 test 실행을 주장하거나 두 트랙 test가 함께 보이면 선택 경계를 위반한다.
❌ progressive_contract Green이면 manifest의 finalState 10_000도 증명된다.
왜 틀리나 packaged test는 1_000에서 300을 처리한 700/300만 assert한다.
바르게 읽기 10_000 finalState는 별도 learner test 또는 사람이 결박한 evidence로 증명한다.
반례 runtime은 domainContract.finalState 문자열을 parse하거나 assert하지 않는다.
❌ history에 XML SHA가 있으니 Red·Green·Cumulative XML 원본이 모두 보존됐다.
왜 틀리나 다음 cleanTest가 build/test-results의 이전 XML을 덮어쓰며 state는 bytes를 복사하지 않는다.
바르게 읽기 각 phase 직후 고유 evidence 경로로 원자 복사하고 hash를 history와 대조한다.
반례 RecordGreen 뒤에는 Red XML 경로가 사라질 수 있다.
❌ Review가 새 test를 실행해 CumulativeGreen을 다시 만들고 Q41·sealed official 결과까지 자동 확인한다.
왜 틀리나 Review는 기존 CumulativeGreen을 전제로 review entry와 leak check만 기록한다. Q41은 별도 PostgreSQL 과제이고 sealed official status는 user-attested다.
바르게 읽기 Review에서는 reviewedPhase와 history 증가만 보고, Q41 native evidence와 USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED sealed evidence를 별도로 판정한다.
반례 Review 뒤 phase는 여전히 CumulativeGreen이고 새 execution/XML·Q41 transcript·official login verification이 생기지 않는다.
STEP 11 / 13
이 코드가 보장하지 않는 것
선택 미결정·10_000 finalState·XML 보존·Review/Q41/sealed official truth처럼 이 코드가 책임지지 않는 일을 분리합니다.
reference asset을 복사했다고 learner authorship이 되지 않는다
이 책임을 맡는 곳: runtime GateUTF-8 BOM은 runtime이 거절한다
이 책임을 맡는 곳: external/human review선택하지 않은 트랙은 N-A_UNSELECTED
이 책임을 맡는 곳: release manifestreference와 learner root는 서로 달라야 한다
이 책임을 맡는 곳: 운영 환경증명하지 않는 범위 — SECURITIES starter CashWallet — available 차감 누락
-
RED comment가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 reserve가 reserved만 늘려 같은 현금을 다시 예약할 수 있는 의도한 Red 반례를 읽는다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 RED comment와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 12 / 13
직접 다시 써보기
뜻 → 조각 → 전체 코드 순서로 다시 씁니다.
1단계 · 뜻부터 복원
- reserve가 reserved만 늘려 같은 현금을 다시 예약할 수 있는 의도한 Red 반례를 읽는다.
- 핵심 값은 availableCash=1_000, reservedCash=0, reserve(300), available remains 1_000, RED comment다.
2단계 · 코드 조각 재조립
- 1. CashWallet.java의 다음 검증 또는 설명 단계를 구성한다
- 3. CashWallet.java의 다음 검증 또는 설명 단계를 구성한다
- 4. CashWallet.java의 다음 검증 또는 설명 단계를 구성한다
- 5. CashWallet.java의 다음 검증 또는 설명 단계를 구성한다
- 6. CashWallet.java의 다음 검증 또는 설명 단계를 구성한다
- 7. CashWallet.java의 다음 검증 또는 설명 단계를 구성한다
- 8. CashWallet.java의 다음 검증 또는 설명 단계를 구성한다
- 9. CashWallet.java의 다음 검증 또는 설명 단계를 구성한다
3단계 · 파일 전체 다시 쓰기
track_learning_stages/securities/w25/starter/src/main/java/com/example/financialcore/securities/CashWallet.java을 새 파일에 다시 쓰고 expected·actual·실패·cleanup·비범위를 주석으로 표시한다.
자가 점검
- 비어 있지 않은 모든 source 줄을 한 번씩 읽었나?
- 기본 트랙을 SECURITIES(증권) 하나로 두고 기본 선택·selected-track evidence·runtime Green을 서로 분리했나?
- Review·Q41·USER_ATTESTED sealed 상태를 자동 성공으로 꾸미지 않았나?
- XML bytes archive와 첫 실패·cleanup 책임을 설명할 수 있나?
STEP 13 / 13
전체 원본 source
감사로 고정한 전체 source를 가감 없이 확인합니다.
원문 정본 전체 source 확인하기
package com.example.financialcore.securities;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import jakarta.persistence.Version;
@Entity
@Table(name = "securities_cash_wallet")
public class CashWallet {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "investor_key", nullable = false, unique = true, length = 64)
private String investorKey;
@Column(name = "available_cash", nullable = false)
private long availableCash;
@Column(name = "reserved_cash", nullable = false)
private long reservedCash;
@Version
private long version;
protected CashWallet() {}
private CashWallet(String investorKey, long availableCash) {
if (investorKey == null || investorKey.isBlank()) throw new IllegalArgumentException("investorKey");
if (availableCash < 0) throw new IllegalArgumentException("availableCash");
this.investorKey = investorKey;
this.availableCash = availableCash;
}
public static CashWallet open(String investorKey, long availableCash) {
return new CashWallet(investorKey, availableCash);
}
public void reserve(long amount) {
if (amount <= 0) throw new IllegalArgumentException("amount");
if (availableCash < amount) throw new IllegalStateException("INSUFFICIENT_AVAILABLE_CASH");
// RED: available cash is not reduced
reservedCash = Math.addExact(reservedCash, amount);
}
public void settle(long reservedAmount, long executedAmount) {
if (reservedAmount <= 0 || executedAmount <= 0 || executedAmount > reservedAmount) {
throw new IllegalArgumentException("settlement amount");
}
if (reservedCash < reservedAmount) throw new IllegalStateException("RESERVATION_MISMATCH");
reservedCash -= reservedAmount;
availableCash = Math.addExact(availableCash, reservedAmount - executedAmount);
}
public void releaseReservation(long amount) {
if (amount <= 0 || reservedCash < amount) throw new IllegalArgumentException("amount");
reservedCash -= amount;
availableCash = Math.addExact(availableCash, amount);
}
public Long getId() { return id; }
public String getInvestorKey() { return investorKey; }
public long getAvailableCash() { return availableCash; }
public long getReservedCash() { return reservedCash; }
}
09CARD starter CardAccount — usedAmount 증가 누락
track_learning_stages/card/w25/starter/src/main/java/com/example/financialcore/card/CardAccount.java
PDF 전문 정본 · learner starter Java · 정본 · W25-F0946줄 연결46줄 번역5 chunks
CARD starter CardAccount — usedAmount 증가 누락
track_learning_stages/card/w25/starter/src/main/java/com/example/financialcore/card/CardAccount.java
PDF 전문 정본 · learner starter Java · 정본 · W25-F09STEP 01 / 13
오늘 이 코드에서 해결할 문제
무엇을 이해해야 하는지 질문부터 잡습니다.
hold가 사용액을 늘리지 않아 같은 한도를 반복 승인할 수 있는 의도한 Red 반례를 읽는다.
- creditLimit=1_000은 어느 source와 실제 결과에서 확인해야 할까?
- 첫 실패를 만드는 조건과 fail-closed 지점은 어디일까?
- 왜 ‘reference asset을 복사했다고 learner authorship이 되지 않는다’를 별도 경계로 남겨야 할까?
creditLimit=1_000usedAmount=0hold(300)used remains 0RED comment왜 필요한가 — CARD starter CardAccount — usedAmount 증가 누락
-
creditLimit=1_000가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 hold가 사용액을 늘리지 않아 같은 한도를 반복 승인할 수 있는 의도한 Red 반례를 읽는다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘reference asset을 복사했다고 learner authorship이 되지 않는다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 creditLimit=1_000와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 02 / 13
아주 짧게: 이 코드는 왜 필요할까?
웹소설 대신 이 코드가 필요한 이유만 두 문단으로 쉽게 봅니다.
사용자의 기본 선택에 따라 이 HTML은 SECURITIES(증권)을 주 트랙으로 읽는다. CARD는 비교용이며 명시적으로 고르면 기본값을 덮어쓸 수 있다. 실제 실행은 최종 선택 한 개를 selected-track.csv·근거·state에 같은 값으로 기록하고 reference와 learner 폴더를 분리한 뒤에만 시작한다. 이 HTML 자체는 Gradle/JUnit을 실행하지 않아 NOT_RUN 상태다.
한 통장만 골라 빨강에서 초록까지 증명하는 일주일
이 파일은 hold가 사용액을 늘리지 않아 같은 한도를 반복 승인할 수 있는 의도한 Red 반례를 읽는다. 눈으로 읽을 때는 각 줄을 검수표 한 칸처럼 보고, 입력과 다음 상태를 놓치지 않는다.
마지막 도장은 hash 확인, 세 test phase의 실제 JUnit 실행, XML bytes archive, 사람 review를 서로 구분한 뒤에만 찍는다. Review는 새 test가 아니며 Q41은 stage runtime 밖의 별도 NOT_RUN 과제, sealed official status는 USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED다. 특히 reference asset을 복사했다고 learner authorship이 되지 않는다
딱 여기까지만 비유와 SECURITIES 기본 배지는 실제 selected-track 근거, Gradle/JUnit 실행, XML bytes 보존, 사람 review, Q41 실행, sealed official 확인을 대신하지 않는다.
STEP 03 / 13
초등학생도 이해하는 설명
생활 비유와 실제 코드의 경계를 함께 확인합니다.
값 1: creditLimit=1_000
이 파일에서 계속 확인할 고정 단서가 creditLimit=1_000다.
- 코드 연결
F09 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- reference asset을 복사했다고 learner authorship이 되지 않는다
값 2: usedAmount=0
이 파일에서 계속 확인할 고정 단서가 usedAmount=0다.
- 코드 연결
F09 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- UTF-8 BOM은 runtime이 거절한다
값 3: hold(300)
이 파일에서 계속 확인할 고정 단서가 hold(300)다.
- 코드 연결
F09 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- 선택하지 않은 트랙은 N-A_UNSELECTED
값 4: used remains 0
이 파일에서 계속 확인할 고정 단서가 used remains 0다.
- 코드 연결
F09 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- reference와 learner root는 서로 달라야 한다
값 5: RED comment
이 파일에서 계속 확인할 고정 단서가 RED comment다.
- 코드 연결
F09 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
STEP 04 / 13
비유 ↔ 코드 전체 연결표
감사 규칙상 연결 대상인 원본 46줄을 빠짐없이 연결합니다.
| 줄 | 정확한 원본 줄 | STARRY 비유 | 실제 뜻·입력·결과·한계 |
|---|---|---|---|
| 1줄F09-L01 | package com. |
출고표 1번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 3줄F09-L03 | import jakarta. |
출고표 3번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 4줄F09-L04 | import jakarta. |
출고표 4번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 5줄F09-L05 | import jakarta. |
출고표 5번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 6줄F09-L06 | import jakarta. |
출고표 6번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 7줄F09-L07 | import jakarta. |
출고표 7번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 8줄F09-L08 | import jakarta. |
출고표 8번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 9줄F09-L09 | import jakarta. |
출고표 9번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 11줄F09-L11 | @Entity |
출고표 11번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 12줄F09-L12 | @Table( |
출고표 12번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 13줄F09-L13 | public class CardAccount { |
출고표 13번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 조건·반복·함수의 실행 block을 연다.
|
| 14줄F09-L14 | @Id |
출고표 14번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 15줄F09-L15 | @GeneratedValue( |
출고표 15번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 16줄F09-L16 | private Long id; |
출고표 16번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 18줄F09-L18 | @Column( |
출고표 18번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 19줄F09-L19 | private String accountKey; |
출고표 19번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 21줄F09-L21 | @Column( |
출고표 21번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 22줄F09-L22 | private long creditLimit; |
출고표 22번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 24줄F09-L24 | @Column( |
출고표 24번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 25줄F09-L25 | private long usedAmount; |
출고표 25번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 27줄F09-L27 | @Version |
출고표 27번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 28줄F09-L28 | private long version; |
출고표 28번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 30줄F09-L30 | protected CardAccount( |
출고표 30번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 32줄F09-L32 | private CardAccount( |
출고표 32번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 조건·반복·함수의 실행 block을 연다.
|
| 33줄F09-L33 | if ( |
출고표 33번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 34줄F09-L34 | if ( |
출고표 34번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 35줄F09-L35 | this. |
출고표 35번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 36줄F09-L36 | this. |
출고표 36번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 37줄F09-L37 | } |
출고표 37번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 39줄F09-L39 | public static CardAccount open( |
출고표 39번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 조건·반복·함수의 실행 block을 연다.
|
| 40줄F09-L40 | return new CardAccount( |
출고표 40번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 41줄F09-L41 | } |
출고표 41번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 43줄F09-L43 | public void hold( |
출고표 43번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 조건·반복·함수의 실행 block을 연다.
|
| 44줄F09-L44 | if ( |
출고표 44번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 45줄F09-L45 | if ( |
출고표 45번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 hold 뒤 가용 한도가 700인지 관찰한다.
|
| 46줄F09-L46 | / |
출고표 46번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 47줄F09-L47 | } |
출고표 47번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 49줄F09-L49 | public void release( |
출고표 49번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 조건·반복·함수의 실행 block을 연다.
|
| 50줄F09-L50 | if ( |
출고표 50번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 51줄F09-L51 | usedAmount -= |
출고표 51번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 52줄F09-L52 | } |
출고표 52번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 54줄F09-L54 | public long availableAmount( |
출고표 54번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 hold 뒤 가용 한도가 700인지 관찰한다.
|
| 55줄F09-L55 | public Long getId( |
출고표 55번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 56줄F09-L56 | public String getAccountKey( |
출고표 56번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 57줄F09-L57 | public long getUsedAmount( |
출고표 57번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 hold 뒤 사용액이 300인지 관찰한다.
|
| 58줄F09-L58 | } |
출고표 58번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
STEP 05 / 13
원본 코드 조각
원본을 5개 의미 조각으로 나누어 그대로 확인합니다.
파일을 한꺼번에 외우지 않고 실행 의미가 이어지는 작은 조각으로 봅니다. 아래 코드는 hash로 고정한 native 정본 source에서 그대로 잘랐습니다.
package com.example.financialcore.card;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import jakarta.persistence.Version;
@Entity
@Table(name = "card_account_template")
public class CardAccount {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "account_key", nullable = false, unique = true, length = 64)
private String accountKey;
@Column(name = "credit_limit", nullable = false)
private long creditLimit;
@Column(name = "used_amount", nullable = false)
private long usedAmount;
@Version
private long version;
protected CardAccount() {}
private CardAccount(String accountKey, long creditLimit) {
if (accountKey == null || accountKey.isBlank()) throw new IllegalArgumentException("accountKey");
if (creditLimit <= 0) throw new IllegalArgumentException("creditLimit");
this.accountKey = accountKey;
this.creditLimit = creditLimit;
}
public static CardAccount open(String accountKey, long creditLimit) {
return new CardAccount(accountKey, creditLimit);
}
public void hold(long amount) {
if (amount <= 0) throw new IllegalArgumentException("amount");
if (availableAmount() < amount) throw new IllegalStateException("INSUFFICIENT_AVAILABLE_LIMIT");
// RED: used amount is not increased
}
public void release(long amount) {
if (amount <= 0 || usedAmount < amount) throw new IllegalArgumentException("amount");
usedAmount -= amount;
}
public long availableAmount() { return creditLimit - usedAmount; }
public Long getId() { return id; }
public String getAccountKey() { return accountKey; }
public long getUsedAmount() { return usedAmount; }
}
STEP 06 / 13
코드 한 줄씩 한국어로 번역
비어 있지 않은 46줄을 모두 한국어로 옮깁니다.
비어 있지 않은 원본 줄은 하나도 생략하지 않습니다.
| 줄 | 원본 | 한국어 번역 |
|---|---|---|
| 1 | package com.example.financialcore.card; | 실행 의미: CardAccount.java의 다음 검증 또는 설명 단계를 구성한다. |
| 3 | import jakarta.persistence.Column; | 실행 의미: CardAccount.java의 다음 검증 또는 설명 단계를 구성한다. |
| 4 | import jakarta.persistence.Entity; | 실행 의미: CardAccount.java의 다음 검증 또는 설명 단계를 구성한다. |
| 5 | import jakarta.persistence.GeneratedValue; | 실행 의미: CardAccount.java의 다음 검증 또는 설명 단계를 구성한다. |
| 6 | import jakarta.persistence.GenerationType; | 실행 의미: CardAccount.java의 다음 검증 또는 설명 단계를 구성한다. |
| 7 | import jakarta.persistence.Id; | 실행 의미: CardAccount.java의 다음 검증 또는 설명 단계를 구성한다. |
| 8 | import jakarta.persistence.Table; | 실행 의미: CardAccount.java의 다음 검증 또는 설명 단계를 구성한다. |
| 9 | import jakarta.persistence.Version; | 실행 의미: CardAccount.java의 다음 검증 또는 설명 단계를 구성한다. |
| 11 | @Entity | 실행 의미: CardAccount.java의 다음 검증 또는 설명 단계를 구성한다. |
| 12 | @Table(name = "card_account_template") | 실행 의미: CardAccount.java의 다음 검증 또는 설명 단계를 구성한다. |
| 13 | public class CardAccount { | 실행 의미: 조건·반복·함수의 실행 block을 연다. |
| 14 | @Id | 실행 의미: CardAccount.java의 다음 검증 또는 설명 단계를 구성한다. |
| 15 | @GeneratedValue(strategy = GenerationType.IDENTITY) | 실행 의미: CardAccount.java의 다음 검증 또는 설명 단계를 구성한다. |
| 16 | private Long id; | 실행 의미: CardAccount.java의 다음 검증 또는 설명 단계를 구성한다. |
| 18 | @Column(name = "account_key", nullable = false, unique = true, length = 64) | 실행 의미: CardAccount.java의 다음 검증 또는 설명 단계를 구성한다. |
| 19 | private String accountKey; | 실행 의미: CardAccount.java의 다음 검증 또는 설명 단계를 구성한다. |
| 21 | @Column(name = "credit_limit", nullable = false) | 실행 의미: CardAccount.java의 다음 검증 또는 설명 단계를 구성한다. |
| 22 | private long creditLimit; | 실행 의미: CardAccount.java의 다음 검증 또는 설명 단계를 구성한다. |
| 24 | @Column(name = "used_amount", nullable = false) | 실행 의미: CardAccount.java의 다음 검증 또는 설명 단계를 구성한다. |
| 25 | private long usedAmount; | 실행 의미: CardAccount.java의 다음 검증 또는 설명 단계를 구성한다. |
| 27 | @Version | 실행 의미: CardAccount.java의 다음 검증 또는 설명 단계를 구성한다. |
| 28 | private long version; | 실행 의미: CardAccount.java의 다음 검증 또는 설명 단계를 구성한다. |
| 30 | protected CardAccount() {} | 실행 의미: CardAccount.java의 다음 검증 또는 설명 단계를 구성한다. |
| 32 | private CardAccount(String accountKey, long creditLimit) { | 실행 의미: 조건·반복·함수의 실행 block을 연다. |
| 33 | if (accountKey == null || accountKey.isBlank()) throw new IllegalArgumentException("accountKey"); | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 34 | if (creditLimit <= 0) throw new IllegalArgumentException("creditLimit"); | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 35 | this.accountKey = accountKey; | 실행 의미: CardAccount.java의 다음 검증 또는 설명 단계를 구성한다. |
| 36 | this.creditLimit = creditLimit; | 실행 의미: CardAccount.java의 다음 검증 또는 설명 단계를 구성한다. |
| 37 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 39 | public static CardAccount open(String accountKey, long creditLimit) { | 실행 의미: 조건·반복·함수의 실행 block을 연다. |
| 40 | return new CardAccount(accountKey, creditLimit); | 실행 의미: CardAccount.java의 다음 검증 또는 설명 단계를 구성한다. |
| 41 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 43 | public void hold(long amount) { | 실행 의미: 조건·반복·함수의 실행 block을 연다. |
| 44 | if (amount <= 0) throw new IllegalArgumentException("amount"); | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 45 | if (availableAmount() < amount) throw new IllegalStateException("INSUFFICIENT_AVAILABLE_LIMIT"); | 실행 의미: hold 뒤 가용 한도가 700인지 관찰한다. |
| 46 | // RED: used amount is not increased | 실행 의미: CardAccount.java의 다음 검증 또는 설명 단계를 구성한다. |
| 47 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 49 | public void release(long amount) { | 실행 의미: 조건·반복·함수의 실행 block을 연다. |
| 50 | if (amount <= 0 || usedAmount < amount) throw new IllegalArgumentException("amount"); | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 51 | usedAmount -= amount; | 실행 의미: CardAccount.java의 다음 검증 또는 설명 단계를 구성한다. |
| 52 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 54 | public long availableAmount() { return creditLimit - usedAmount; } | 실행 의미: hold 뒤 가용 한도가 700인지 관찰한다. |
| 55 | public Long getId() { return id; } | 실행 의미: CardAccount.java의 다음 검증 또는 설명 단계를 구성한다. |
| 56 | public String getAccountKey() { return accountKey; } | 실행 의미: CardAccount.java의 다음 검증 또는 설명 단계를 구성한다. |
| 57 | public long getUsedAmount() { return usedAmount; } | 실행 의미: hold 뒤 사용액이 300인지 관찰한다. |
| 58 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
STEP 07 / 13
기존 수준의 한 줄 읽기·문법 해부
쉬운 설명 다음에 문법과 실행 순서를 정밀하게 읽습니다.
한 줄로 읽기CARD starter CardAccount — usedAmount 증가 누락는 hold가 사용액을 늘리지 않아 같은 한도를 반복 승인할 수 있는 의도한 Red 반례를 읽는다.
문법 해부
- .java 문법에서 선언·조건·pipeline·block 경계를 먼저 나눈다.
- manifest의 finalState와 packaged progressive test의 1_000→700/300 oracle을 서로 다른 계약으로 읽는다.
- phase state·native exit·JUnit XML hash·보존된 XML bytes·사람 판정·USER_ATTESTED external status를 서로 대체하지 않는다.
실행 순서
- 기본 트랙은 SECURITIES(증권)이며, 명시적 CARD 선택은 기본값을 덮어쓴다. 실제 실행 전 최종 선택 한 개를 selected-track.csv·근거·state에 같은 값으로 기록하고 서로 다른 reference/learner root를 확인한다.
- Prepare→VerifyStarter→RecordRed→VerifySolution→RecordGreen→Cumulative→Review 순서를 지킨다.
- test를 소유한 세 phase에서만 native exit와 exact JUnit XML 수치를 판정한다.
- 다음 cleanTest 전에 XML bytes를 고유 경로에 보존하고 runtime history hash와 다시 묶는다. Review·Q41·sealed official evidence는 각자의 별도 owner와 검증 수준으로 남긴다.
W25 조각별 정밀 해설
F09-C01 · 원문 1–12줄
- 문법 해부
- .java 문법으로 1–12줄의 선언·조건·phase·assert block을 나눈다.
- 실제 값 추적
- creditLimit=1_000, usedAmount=0, hold(300)를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- 기본 SECURITIES 또는 명시적으로 덮어쓴 CARD 중 최종 선택 한 개의 selected-track evidence와 runtime 결과에서 expected와 actual이 일치하고 owner evidence가 같은 run/hash 및 보존 XML에 연결되는 경우다. 기본/덮어쓰기 표시만 있고 실행 evidence가 없으면 NOT_RUN이다.
- 틀린 예·반례
- reference asset을 복사했다고 learner authorship이 되지 않는다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- phase 이름·manifest finalState·history hash·exit0 하나를 W25 증거 전체와 같다고 보지 않는다.
- 하지 않는 일
- reference asset을 복사했다고 learner authorship이 되지 않는다; UTF-8 BOM은 runtime이 거절한다; 선택하지 않은 트랙은 N-A_UNSELECTED; reference와 learner root는 서로 달라야 한다; 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다; 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
- 다음 연결
- 다음 조각 또는 F09 evidence 판정으로 상태를 넘긴다.
F09-C02 · 원문 13–24줄
- 문법 해부
- .java 문법으로 13–24줄의 선언·조건·phase·assert block을 나눈다.
- 실제 값 추적
- creditLimit=1_000, usedAmount=0, hold(300)를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- 기본 SECURITIES 또는 명시적으로 덮어쓴 CARD 중 최종 선택 한 개의 selected-track evidence와 runtime 결과에서 expected와 actual이 일치하고 owner evidence가 같은 run/hash 및 보존 XML에 연결되는 경우다. 기본/덮어쓰기 표시만 있고 실행 evidence가 없으면 NOT_RUN이다.
- 틀린 예·반례
- reference asset을 복사했다고 learner authorship이 되지 않는다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- phase 이름·manifest finalState·history hash·exit0 하나를 W25 증거 전체와 같다고 보지 않는다.
- 하지 않는 일
- reference asset을 복사했다고 learner authorship이 되지 않는다; UTF-8 BOM은 runtime이 거절한다; 선택하지 않은 트랙은 N-A_UNSELECTED; reference와 learner root는 서로 달라야 한다; 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다; 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
- 다음 연결
- 다음 조각 또는 F09 evidence 판정으로 상태를 넘긴다.
F09-C03 · 원문 25–36줄
- 문법 해부
- .java 문법으로 25–36줄의 선언·조건·phase·assert block을 나눈다.
- 실제 값 추적
- creditLimit=1_000, usedAmount=0, hold(300)를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- 기본 SECURITIES 또는 명시적으로 덮어쓴 CARD 중 최종 선택 한 개의 selected-track evidence와 runtime 결과에서 expected와 actual이 일치하고 owner evidence가 같은 run/hash 및 보존 XML에 연결되는 경우다. 기본/덮어쓰기 표시만 있고 실행 evidence가 없으면 NOT_RUN이다.
- 틀린 예·반례
- reference asset을 복사했다고 learner authorship이 되지 않는다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- phase 이름·manifest finalState·history hash·exit0 하나를 W25 증거 전체와 같다고 보지 않는다.
- 하지 않는 일
- reference asset을 복사했다고 learner authorship이 되지 않는다; UTF-8 BOM은 runtime이 거절한다; 선택하지 않은 트랙은 N-A_UNSELECTED; reference와 learner root는 서로 달라야 한다; 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다; 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
- 다음 연결
- 다음 조각 또는 F09 evidence 판정으로 상태를 넘긴다.
F09-C04 · 원문 37–48줄
- 문법 해부
- .java 문법으로 37–48줄의 선언·조건·phase·assert block을 나눈다.
- 실제 값 추적
- creditLimit=1_000, usedAmount=0, hold(300)를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- 기본 SECURITIES 또는 명시적으로 덮어쓴 CARD 중 최종 선택 한 개의 selected-track evidence와 runtime 결과에서 expected와 actual이 일치하고 owner evidence가 같은 run/hash 및 보존 XML에 연결되는 경우다. 기본/덮어쓰기 표시만 있고 실행 evidence가 없으면 NOT_RUN이다.
- 틀린 예·반례
- reference asset을 복사했다고 learner authorship이 되지 않는다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- phase 이름·manifest finalState·history hash·exit0 하나를 W25 증거 전체와 같다고 보지 않는다.
- 하지 않는 일
- reference asset을 복사했다고 learner authorship이 되지 않는다; UTF-8 BOM은 runtime이 거절한다; 선택하지 않은 트랙은 N-A_UNSELECTED; reference와 learner root는 서로 달라야 한다; 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다; 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
- 다음 연결
- 다음 조각 또는 F09 evidence 판정으로 상태를 넘긴다.
F09-C05 · 원문 49–58줄
- 문법 해부
- .java 문법으로 49–58줄의 선언·조건·phase·assert block을 나눈다.
- 실제 값 추적
- creditLimit=1_000, usedAmount=0, hold(300)를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- 기본 SECURITIES 또는 명시적으로 덮어쓴 CARD 중 최종 선택 한 개의 selected-track evidence와 runtime 결과에서 expected와 actual이 일치하고 owner evidence가 같은 run/hash 및 보존 XML에 연결되는 경우다. 기본/덮어쓰기 표시만 있고 실행 evidence가 없으면 NOT_RUN이다.
- 틀린 예·반례
- reference asset을 복사했다고 learner authorship이 되지 않는다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- phase 이름·manifest finalState·history hash·exit0 하나를 W25 증거 전체와 같다고 보지 않는다.
- 하지 않는 일
- reference asset을 복사했다고 learner authorship이 되지 않는다; UTF-8 BOM은 runtime이 거절한다; 선택하지 않은 트랙은 N-A_UNSELECTED; reference와 learner root는 서로 달라야 한다; 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다; 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
- 다음 연결
- 다음 조각 또는 F09 evidence 판정으로 상태를 넘긴다.
실행 순서 — CARD starter CardAccount — usedAmount 증가 누락
-
usedAmount=0가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 hold가 사용액을 늘리지 않아 같은 한도를 반복 승인할 수 있는 의도한 Red 반례를 읽는다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘UTF-8 BOM은 runtime이 거절한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 usedAmount=0와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 08 / 13
실제 값 따라가기
같은 입력값이 어느 줄을 지나 어떤 결과가 되는지 추적합니다.
| 순서 | 들어온 값 | 코드가 하는 일 | 나온 값·상태 | 경계 |
|---|---|---|---|---|
| 입력 | creditLimit=1_000 | source 계약에 대입 | F09 실행/설명 시작 상태 | reference asset을 복사했다고 learner authorship이 되지 않는다 |
| 검증 | usedAmount=0 | expected와 actual 또는 형식 대조 | 통과 또는 첫 mismatch | UTF-8 BOM은 runtime이 거절한다 |
| 증거 | RED comment | marker·hash·row를 같은 run에 연결 | 범위가 적힌 evidence 후보 | 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다 |
실제 값 — CARD starter CardAccount — usedAmount 증가 누락
-
hold(300)가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 hold가 사용액을 늘리지 않아 같은 한도를 반복 승인할 수 있는 의도한 Red 반례를 읽는다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘선택하지 않은 트랙은 N-A_UNSELECTED’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 hold(300)와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 09 / 13
Gradle·JUnit XML·PowerShell·SQL 내부에서 벌어지는 일
세 test phase, XML bytes archive, Review, 별도 Q41, USER_ATTESTED sealed 결과의 owner와 증명 범위를 구분합니다.
CardAccount.java bytes와 track·phase·hash 계약을 읽는다.
SECURITIES 기본 선택과 파일 존재·phase 이름만으로 runtime Green을 주장할 수 없다. 실제 selected-track evidence와 실행 결과는 별도다.RecordRed·RecordGreen·Cumulative에서만 native exit와 exact JUnit XML을 만든다.
reference asset을 복사했다고 learner authorship이 되지 않는다XML bytes를 고유 파일로 보존하고 history hash와 묶은 뒤, Review는 기존 CumulativeGreen만 인용한다. Q41은 별도 PostgreSQL evidence, sealed official status는 user-attested evidence로 남긴다.
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다첫 실패 경계 — CARD starter CardAccount — usedAmount 증가 누락
-
used remains 0가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 hold가 사용액을 늘리지 않아 같은 한도를 반복 승인할 수 있는 의도한 Red 반례를 읽는다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘reference와 learner root는 서로 달라야 한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 used remains 0와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 10 / 13
흔한 착각과 틀린 예
그럴듯하지만 틀린 해석을 반례로 고칩니다.
❌ Prepare·VerifyStarter·VerifySolution·Review도 Gradle을 실행해 Green을 만든다.
왜 틀리나 runtime에서 test 실행을 소유하는 phase는 RecordRed·RecordGreen·Cumulative뿐이다.
바르게 읽기 각 phase history의 execution 유무와 mode를 직접 확인한다.
반례 VerifySolution은 solution hash만 검증하므로 새 JUnit XML이 없어야 정상이다.
❌ 기본 트랙이 SECURITIES이므로 CARD도 함께 실행해도 되고, 기본 배지만으로 runtime 선택·실행 증거가 완성된다.
왜 틀리나 W25 계약은 실제 사용자 근거가 있는 선택 트랙 하나와 반대 트랙 leak 부재를 요구한다.
바르게 읽기 기본 선택은 SECURITIES(증권)이며 명시적 CARD 선택은 덮어쓰기다. 실행 전 최종 선택 한 개를 selected-track.csv·근거·state에 같은 값으로 고정한다.
반례 SECURITIES 기본 배지만 보고 test 실행을 주장하거나 두 트랙 test가 함께 보이면 선택 경계를 위반한다.
❌ progressive_contract Green이면 manifest의 finalState 10_000도 증명된다.
왜 틀리나 packaged test는 1_000에서 300을 처리한 700/300만 assert한다.
바르게 읽기 10_000 finalState는 별도 learner test 또는 사람이 결박한 evidence로 증명한다.
반례 runtime은 domainContract.finalState 문자열을 parse하거나 assert하지 않는다.
❌ history에 XML SHA가 있으니 Red·Green·Cumulative XML 원본이 모두 보존됐다.
왜 틀리나 다음 cleanTest가 build/test-results의 이전 XML을 덮어쓰며 state는 bytes를 복사하지 않는다.
바르게 읽기 각 phase 직후 고유 evidence 경로로 원자 복사하고 hash를 history와 대조한다.
반례 RecordGreen 뒤에는 Red XML 경로가 사라질 수 있다.
❌ Review가 새 test를 실행해 CumulativeGreen을 다시 만들고 Q41·sealed official 결과까지 자동 확인한다.
왜 틀리나 Review는 기존 CumulativeGreen을 전제로 review entry와 leak check만 기록한다. Q41은 별도 PostgreSQL 과제이고 sealed official status는 user-attested다.
바르게 읽기 Review에서는 reviewedPhase와 history 증가만 보고, Q41 native evidence와 USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED sealed evidence를 별도로 판정한다.
반례 Review 뒤 phase는 여전히 CumulativeGreen이고 새 execution/XML·Q41 transcript·official login verification이 생기지 않는다.
STEP 11 / 13
이 코드가 보장하지 않는 것
선택 미결정·10_000 finalState·XML 보존·Review/Q41/sealed official truth처럼 이 코드가 책임지지 않는 일을 분리합니다.
reference asset을 복사했다고 learner authorship이 되지 않는다
이 책임을 맡는 곳: runtime GateUTF-8 BOM은 runtime이 거절한다
이 책임을 맡는 곳: external/human review선택하지 않은 트랙은 N-A_UNSELECTED
이 책임을 맡는 곳: release manifestreference와 learner root는 서로 달라야 한다
이 책임을 맡는 곳: 운영 환경증명하지 않는 범위 — CARD starter CardAccount — usedAmount 증가 누락
-
RED comment가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 hold가 사용액을 늘리지 않아 같은 한도를 반복 승인할 수 있는 의도한 Red 반례를 읽는다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 RED comment와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 12 / 13
직접 다시 써보기
뜻 → 조각 → 전체 코드 순서로 다시 씁니다.
1단계 · 뜻부터 복원
- hold가 사용액을 늘리지 않아 같은 한도를 반복 승인할 수 있는 의도한 Red 반례를 읽는다.
- 핵심 값은 creditLimit=1_000, usedAmount=0, hold(300), used remains 0, RED comment다.
2단계 · 코드 조각 재조립
- 1. CardAccount.java의 다음 검증 또는 설명 단계를 구성한다
- 3. CardAccount.java의 다음 검증 또는 설명 단계를 구성한다
- 4. CardAccount.java의 다음 검증 또는 설명 단계를 구성한다
- 5. CardAccount.java의 다음 검증 또는 설명 단계를 구성한다
- 6. CardAccount.java의 다음 검증 또는 설명 단계를 구성한다
- 7. CardAccount.java의 다음 검증 또는 설명 단계를 구성한다
- 8. CardAccount.java의 다음 검증 또는 설명 단계를 구성한다
- 9. CardAccount.java의 다음 검증 또는 설명 단계를 구성한다
3단계 · 파일 전체 다시 쓰기
track_learning_stages/card/w25/starter/src/main/java/com/example/financialcore/card/CardAccount.java을 새 파일에 다시 쓰고 expected·actual·실패·cleanup·비범위를 주석으로 표시한다.
자가 점검
- 비어 있지 않은 모든 source 줄을 한 번씩 읽었나?
- 기본 트랙을 SECURITIES(증권) 하나로 두고 기본 선택·selected-track evidence·runtime Green을 서로 분리했나?
- Review·Q41·USER_ATTESTED sealed 상태를 자동 성공으로 꾸미지 않았나?
- XML bytes archive와 첫 실패·cleanup 책임을 설명할 수 있나?
STEP 13 / 13
전체 원본 source
감사로 고정한 전체 source를 가감 없이 확인합니다.
원문 정본 전체 source 확인하기
package com.example.financialcore.card;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import jakarta.persistence.Version;
@Entity
@Table(name = "card_account_template")
public class CardAccount {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "account_key", nullable = false, unique = true, length = 64)
private String accountKey;
@Column(name = "credit_limit", nullable = false)
private long creditLimit;
@Column(name = "used_amount", nullable = false)
private long usedAmount;
@Version
private long version;
protected CardAccount() {}
private CardAccount(String accountKey, long creditLimit) {
if (accountKey == null || accountKey.isBlank()) throw new IllegalArgumentException("accountKey");
if (creditLimit <= 0) throw new IllegalArgumentException("creditLimit");
this.accountKey = accountKey;
this.creditLimit = creditLimit;
}
public static CardAccount open(String accountKey, long creditLimit) {
return new CardAccount(accountKey, creditLimit);
}
public void hold(long amount) {
if (amount <= 0) throw new IllegalArgumentException("amount");
if (availableAmount() < amount) throw new IllegalStateException("INSUFFICIENT_AVAILABLE_LIMIT");
// RED: used amount is not increased
}
public void release(long amount) {
if (amount <= 0 || usedAmount < amount) throw new IllegalArgumentException("amount");
usedAmount -= amount;
}
public long availableAmount() { return creditLimit - usedAmount; }
public Long getId() { return id; }
public String getAccountKey() { return accountKey; }
public long getUsedAmount() { return usedAmount; }
}
10D2 VerifyStarter — starter canonical/raw hash만 검증
illustrative/powershell/W25-D2-verify-starter.ps1
학습용 예시 · W25 phase wrapper · 정본 답안 아님 · 로컬 미실행 · 학습용 예시 · 정본 답안 아님 · NOT_RUN · W25-F1025줄 연결25줄 번역3 chunks
D2 VerifyStarter — starter canonical/raw hash만 검증
illustrative/powershell/W25-D2-verify-starter.ps1
학습용 예시 · W25 phase wrapper · 정본 답안 아님 · 로컬 미실행 · 학습용 예시 · 정본 답안 아님 · NOT_RUN · W25-F10STEP 01 / 13
오늘 이 코드에서 해결할 문제
무엇을 이해해야 하는지 질문부터 잡습니다.
Prepared 이후 learner가 직접 입력한 선택 트랙 starter hash와 소유권을 확인하되 새 test 실행이 없음을 확인한다.
- Prepared은 어느 source와 실제 결과에서 확인해야 할까?
- 첫 실패를 만드는 조건과 fail-closed 지점은 어디일까?
- 왜 ‘compile 가능성과 Red XML은 아직 증명되지 않는다’를 별도 경계로 남겨야 할까?
PreparedStarterVerifiedauthoredTargetcanonical/raw SHA-256runtime_claim=false왜 필요한가 — raw hash만 검증
-
Prepared가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 Prepared 이후 learner가 직접 입력한 선택 트랙 starter hash와 소유권을 확인하되 새 test 실행이 없음을 확인한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘compile 가능성과 Red XML은 아직 증명되지 않는다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 Prepared와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 02 / 13
아주 짧게: 이 코드는 왜 필요할까?
웹소설 대신 이 코드가 필요한 이유만 두 문단으로 쉽게 봅니다.
사용자의 기본 선택에 따라 이 HTML은 SECURITIES(증권)을 주 트랙으로 읽는다. CARD는 비교용이며 명시적으로 고르면 기본값을 덮어쓸 수 있다. 실제 실행은 최종 선택 한 개를 selected-track.csv·근거·state에 같은 값으로 기록하고 reference와 learner 폴더를 분리한 뒤에만 시작한다. 이 HTML 자체는 Gradle/JUnit을 실행하지 않아 NOT_RUN 상태다.
한 통장만 골라 빨강에서 초록까지 증명하는 일주일
이 파일은 Prepared 이후 learner가 직접 입력한 선택 트랙 starter hash와 소유권을 확인하되 새 test 실행이 없음을 확인한다. 눈으로 읽을 때는 각 줄을 검수표 한 칸처럼 보고, 입력과 다음 상태를 놓치지 않는다.
마지막 도장은 hash 확인, 세 test phase의 실제 JUnit 실행, XML bytes archive, 사람 review를 서로 구분한 뒤에만 찍는다. Review는 새 test가 아니며 Q41은 stage runtime 밖의 별도 NOT_RUN 과제, sealed official status는 USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED다. 특히 compile 가능성과 Red XML은 아직 증명되지 않는다
딱 여기까지만 비유와 SECURITIES 기본 배지는 실제 selected-track 근거, Gradle/JUnit 실행, XML bytes 보존, 사람 review, Q41 실행, sealed official 확인을 대신하지 않는다.
STEP 03 / 13
초등학생도 이해하는 설명
생활 비유와 실제 코드의 경계를 함께 확인합니다.
값 1: Prepared
이 파일에서 계속 확인할 고정 단서가 Prepared다.
- 코드 연결
F10 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- compile 가능성과 Red XML은 아직 증명되지 않는다
값 2: StarterVerified
이 파일에서 계속 확인할 고정 단서가 StarterVerified다.
- 코드 연결
F10 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- README BOM 허용 문구보다 runtime 무 BOM 규칙이 우선한다
값 3: authoredTarget
이 파일에서 계속 확인할 고정 단서가 authoredTarget다.
- 코드 연결
F10 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- reference와 learner root는 서로 달라야 한다
값 4: canonical/raw SHA-256
이 파일에서 계속 확인할 고정 단서가 canonical/raw SHA-256다.
- 코드 연결
F10 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
값 5: runtime_claim=false
이 파일에서 계속 확인할 고정 단서가 runtime_claim=false다.
- 코드 연결
F10 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
STEP 04 / 13
비유 ↔ 코드 전체 연결표
감사 규칙상 연결 대상인 원본 25줄을 빠짐없이 연결합니다.
| 줄 | 정확한 원본 줄 | STARRY 비유 | 실제 뜻·입력·결과·한계 |
|---|---|---|---|
| 1줄F10-L01 | # W25 PDF p8-p17의 VerifyStarter 흐름을 정리한 학습용 예시다. |
출고표 1번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 starter canonical/raw hash만 검증하고 Gradle은 실행하지 않는 phase다.
|
| 2줄F10-L02 | # 이 phase는 starter bytes/ |
출고표 2번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다.
|
| 3줄F10-L03 | $ErrorActionPreference = |
출고표 3번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 PowerShell 오류를 계속 진행하지 않고 중단시키는 기본 정책을 둔다.
|
| 4줄F10-L04 | $ReferenceRoot = |
출고표 4번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 입력 경로를 실제 절대 경로로 확인한다.
|
| 5줄F10-L05 | $LearnerRoot = |
출고표 5번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 입력 경로를 실제 절대 경로로 확인한다.
|
| 6줄F10-L06 | if ( |
출고표 6번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 조건·반복·함수의 실행 block을 연다.
|
| 7줄F10-L07 | throw 'reference and learner roots must be different' |
출고표 7번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 8줄F10-L08 | } |
출고표 8번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 9줄F10-L09 | $Before = |
출고표 9번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 JSON text를 필드로 접근 가능한 PowerShell object로 바꾼다.
|
| 10줄F10-L10 | if ( |
출고표 10번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 starter canonical/raw hash만 검증하고 Gradle은 실행하지 않는 phase다.
|
| 12줄F10-L12 | $Runner = |
출고표 12번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 13줄F10-L13 | & powershell. |
출고표 13번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W25-D2-verify-starter.ps1의 다음 검증 또는 설명 단계를 구성한다.
|
| 14줄F10-L14 | -ReferenceRoot $ReferenceRoot -LearnerRoot $LearnerRoot -Week 25 -Phase VerifyStarter -TimeoutSeconds 1200 |
출고표 14번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 starter canonical/raw hash만 검증하고 Gradle은 실행하지 않는 phase다.
|
| 15줄F10-L15 | if ( |
출고표 15번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 starter canonical/raw hash만 검증하고 Gradle은 실행하지 않는 phase다.
|
| 17줄F10-L17 | $StatePath = |
출고표 17번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 18줄F10-L18 | $State = |
출고표 18번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 JSON text를 필드로 접근 가능한 PowerShell object로 바꾼다.
|
| 19줄F10-L19 | $Entry = |
출고표 19번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 20줄F10-L20 | if ( |
출고표 20번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 starter canonical/raw hash만 검증하고 Gradle은 실행하지 않는 phase다.
|
| 21줄F10-L21 | throw 'W25 VerifyStarter state mismatch' |
출고표 21번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 starter canonical/raw hash만 검증하고 Gradle은 실행하지 않는 phase다.
|
| 22줄F10-L22 | } |
출고표 22번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 23줄F10-L23 | if ( |
출고표 23번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 학습자가 직접 소유하는 main Java 경로와 starter/solution hash를 묶는다.
|
| 24줄F10-L24 | throw 'VerifyStarter must record authoredTarget without execution evidence' |
출고표 24번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 학습자가 직접 소유하는 main Java 경로와 starter/solution hash를 묶는다.
|
| 25줄F10-L25 | } |
출고표 25번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 26줄F10-L26 | $Hash = |
출고표 26번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 현재 bytes를 64자리 digest로 evidence에 결박한다.
|
| 27줄F10-L27 | "W25_STARTER_HASH_VERIFIED phase= |
출고표 27번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 현재 bytes를 64자리 digest로 evidence에 결박한다.
|
STEP 05 / 13
원본 코드 조각
원본을 3개 의미 조각으로 나누어 그대로 확인합니다.
파일을 한꺼번에 외우지 않고 실행 의미가 이어지는 작은 조각으로 봅니다. 아래 코드는 prompt·fixture·가정을 밝힌 학습용 예시 source이며, 제공 정본 답안이나 실행 결과가 아닌 NOT_RUN 자료입니다.
# W25 PDF p8-p17의 VerifyStarter 흐름을 정리한 학습용 예시다.
# 이 phase는 starter bytes/hash와 leak 경계를 검증하지만 Gradle test를 실행하지 않는다.
$ErrorActionPreference = 'Stop'
$ReferenceRoot = (Resolve-Path -LiteralPath $env:FINANCIAL_IT_REFERENCE_ROOT).Path
$LearnerRoot = (Resolve-Path -LiteralPath $env:FINANCIAL_IT_LEARNER_ROOT).Path
if ([string]::Equals($ReferenceRoot, $LearnerRoot, [StringComparison]::OrdinalIgnoreCase)) {
throw 'reference and learner roots must be different'
}
$Before = Get-Content -Raw -LiteralPath (Join-Path $LearnerRoot '.track-learning-stage.json') | ConvertFrom-Json
if ($Before.week -ne 25 -or $Before.phase -cne 'Prepared') { throw 'VerifyStarter requires Prepared' }
$Runner = Join-Path $ReferenceRoot 'scripts\apply-track-learning-stage.ps1'
& powershell.exe -NoProfile -ExecutionPolicy Bypass -File $Runner `
-ReferenceRoot $ReferenceRoot -LearnerRoot $LearnerRoot -Week 25 -Phase VerifyStarter -TimeoutSeconds 1200
if ($LASTEXITCODE -ne 0) { throw "W25 VerifyStarter native exit=$LASTEXITCODE" }
$StatePath = Join-Path $LearnerRoot '.track-learning-stage.json'
$State = Get-Content -Raw -LiteralPath $StatePath | ConvertFrom-Json
$Entry = @($State.history)[-1]
if ($State.phase -cne 'StarterVerified' -or $Entry.phase -cne 'VerifyStarter') {
throw 'W25 VerifyStarter state mismatch'
}
if ($null -eq $Entry.authoredTarget -or $null -ne $Entry.execution) {
throw 'VerifyStarter must record authoredTarget without execution evidence'
}
$Hash = (Get-FileHash -LiteralPath $StatePath -Algorithm SHA256).Hash.ToLowerInvariant()
"W25_STARTER_HASH_VERIFIED phase=StarterVerified runtime_claim=false state_sha256=$Hash"
STEP 06 / 13
코드 한 줄씩 한국어로 번역
비어 있지 않은 25줄을 모두 한국어로 옮깁니다.
비어 있지 않은 원본 줄은 하나도 생략하지 않습니다.
| 줄 | 원본 | 한국어 번역 |
|---|---|---|
| 1 | # W25 PDF p8-p17의 VerifyStarter 흐름을 정리한 학습용 예시다. | 문서 의미: starter canonical/raw hash만 검증하고 Gradle은 실행하지 않는 phase다. |
| 2 | # 이 phase는 starter bytes/hash와 leak 경계를 검증하지만 Gradle test를 실행하지 않는다. | 문서 의미: 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다. |
| 3 | $ErrorActionPreference = 'Stop' | 실행 의미: PowerShell 오류를 계속 진행하지 않고 중단시키는 기본 정책을 둔다. |
| 4 | $ReferenceRoot = (Resolve-Path -LiteralPath $env:FINANCIAL_IT_REFERENCE_ROOT).Path | 실행 의미: 입력 경로를 실제 절대 경로로 확인한다. |
| 5 | $LearnerRoot = (Resolve-Path -LiteralPath $env:FINANCIAL_IT_LEARNER_ROOT).Path | 실행 의미: 입력 경로를 실제 절대 경로로 확인한다. |
| 6 | if ([string]::Equals($ReferenceRoot, $LearnerRoot, [StringComparison]::OrdinalIgnoreCase)) { | 실행 의미: 조건·반복·함수의 실행 block을 연다. |
| 7 | throw 'reference and learner roots must be different' | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 8 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 9 | $Before = Get-Content -Raw -LiteralPath (Join-Path $LearnerRoot '.track-learning-stage.json') | ConvertFrom-Json | 실행 의미: JSON text를 필드로 접근 가능한 PowerShell object로 바꾼다. |
| 10 | if ($Before.week -ne 25 -or $Before.phase -cne 'Prepared') { throw 'VerifyStarter requires Prepared' } | 실행 의미: starter canonical/raw hash만 검증하고 Gradle은 실행하지 않는 phase다. |
| 12 | $Runner = Join-Path $ReferenceRoot 'scripts\apply-track-learning-stage.ps1' | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 13 | & powershell.exe -NoProfile -ExecutionPolicy Bypass -File $Runner ` | 실행 의미: W25-D2-verify-starter.ps1의 다음 검증 또는 설명 단계를 구성한다. |
| 14 | -ReferenceRoot $ReferenceRoot -LearnerRoot $LearnerRoot -Week 25 -Phase VerifyStarter -TimeoutSeconds 1200 | 실행 의미: starter canonical/raw hash만 검증하고 Gradle은 실행하지 않는 phase다. |
| 15 | if ($LASTEXITCODE -ne 0) { throw "W25 VerifyStarter native exit=$LASTEXITCODE" } | 실행 의미: starter canonical/raw hash만 검증하고 Gradle은 실행하지 않는 phase다. |
| 17 | $StatePath = Join-Path $LearnerRoot '.track-learning-stage.json' | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 18 | $State = Get-Content -Raw -LiteralPath $StatePath | ConvertFrom-Json | 실행 의미: JSON text를 필드로 접근 가능한 PowerShell object로 바꾼다. |
| 19 | $Entry = @($State.history)[-1] | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 20 | if ($State.phase -cne 'StarterVerified' -or $Entry.phase -cne 'VerifyStarter') { | 실행 의미: starter canonical/raw hash만 검증하고 Gradle은 실행하지 않는 phase다. |
| 21 | throw 'W25 VerifyStarter state mismatch' | 실행 의미: starter canonical/raw hash만 검증하고 Gradle은 실행하지 않는 phase다. |
| 22 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 23 | if ($null -eq $Entry.authoredTarget -or $null -ne $Entry.execution) { | 실행 의미: 학습자가 직접 소유하는 main Java 경로와 starter/solution hash를 묶는다. |
| 24 | throw 'VerifyStarter must record authoredTarget without execution evidence' | 실행 의미: 학습자가 직접 소유하는 main Java 경로와 starter/solution hash를 묶는다. |
| 25 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 26 | $Hash = (Get-FileHash -LiteralPath $StatePath -Algorithm SHA256).Hash.ToLowerInvariant() | 실행 의미: 현재 bytes를 64자리 digest로 evidence에 결박한다. |
| 27 | "W25_STARTER_HASH_VERIFIED phase=StarterVerified runtime_claim=false state_sha256=$Hash" | 실행 의미: 현재 bytes를 64자리 digest로 evidence에 결박한다. |
STEP 07 / 13
기존 수준의 한 줄 읽기·문법 해부
쉬운 설명 다음에 문법과 실행 순서를 정밀하게 읽습니다.
한 줄로 읽기D2 VerifyStarter — starter canonical/raw hash만 검증는 Prepared 이후 learner가 직접 입력한 선택 트랙 starter hash와 소유권을 확인하되 새 test 실행이 없음을 확인한다.
문법 해부
- .ps1 문법에서 선언·조건·pipeline·block 경계를 먼저 나눈다.
- manifest의 finalState와 packaged progressive test의 1_000→700/300 oracle을 서로 다른 계약으로 읽는다.
- phase state·native exit·JUnit XML hash·보존된 XML bytes·사람 판정·USER_ATTESTED external status를 서로 대체하지 않는다.
실행 순서
- 기본 트랙은 SECURITIES(증권)이며, 명시적 CARD 선택은 기본값을 덮어쓴다. 실제 실행 전 최종 선택 한 개를 selected-track.csv·근거·state에 같은 값으로 기록하고 서로 다른 reference/learner root를 확인한다.
- Prepare→VerifyStarter→RecordRed→VerifySolution→RecordGreen→Cumulative→Review 순서를 지킨다.
- test를 소유한 세 phase에서만 native exit와 exact JUnit XML 수치를 판정한다.
- 다음 cleanTest 전에 XML bytes를 고유 경로에 보존하고 runtime history hash와 다시 묶는다. Review·Q41·sealed official evidence는 각자의 별도 owner와 검증 수준으로 남긴다.
W25 조각별 정밀 해설
F10-C01 · 원문 1–12줄
- 문법 해부
- .ps1 문법으로 1–12줄의 선언·조건·phase·assert block을 나눈다.
- 실제 값 추적
- Prepared, StarterVerified, authoredTarget를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- 기본 SECURITIES 또는 명시적으로 덮어쓴 CARD 중 최종 선택 한 개의 selected-track evidence와 runtime 결과에서 expected와 actual이 일치하고 owner evidence가 같은 run/hash 및 보존 XML에 연결되는 경우다. 기본/덮어쓰기 표시만 있고 실행 evidence가 없으면 NOT_RUN이다.
- 틀린 예·반례
- compile 가능성과 Red XML은 아직 증명되지 않는다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- phase 이름·manifest finalState·history hash·exit0 하나를 W25 증거 전체와 같다고 보지 않는다.
- 하지 않는 일
- compile 가능성과 Red XML은 아직 증명되지 않는다; README BOM 허용 문구보다 runtime 무 BOM 규칙이 우선한다; reference와 learner root는 서로 달라야 한다; 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다; 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
- 다음 연결
- 다음 조각 또는 F10 evidence 판정으로 상태를 넘긴다.
F10-C02 · 원문 13–24줄
- 문법 해부
- .ps1 문법으로 13–24줄의 선언·조건·phase·assert block을 나눈다.
- 실제 값 추적
- Prepared, StarterVerified, authoredTarget를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- 기본 SECURITIES 또는 명시적으로 덮어쓴 CARD 중 최종 선택 한 개의 selected-track evidence와 runtime 결과에서 expected와 actual이 일치하고 owner evidence가 같은 run/hash 및 보존 XML에 연결되는 경우다. 기본/덮어쓰기 표시만 있고 실행 evidence가 없으면 NOT_RUN이다.
- 틀린 예·반례
- compile 가능성과 Red XML은 아직 증명되지 않는다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- phase 이름·manifest finalState·history hash·exit0 하나를 W25 증거 전체와 같다고 보지 않는다.
- 하지 않는 일
- compile 가능성과 Red XML은 아직 증명되지 않는다; README BOM 허용 문구보다 runtime 무 BOM 규칙이 우선한다; reference와 learner root는 서로 달라야 한다; 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다; 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
- 다음 연결
- 다음 조각 또는 F10 evidence 판정으로 상태를 넘긴다.
F10-C03 · 원문 25–27줄
- 문법 해부
- .ps1 문법으로 25–27줄의 선언·조건·phase·assert block을 나눈다.
- 실제 값 추적
- Prepared, StarterVerified, authoredTarget를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- 기본 SECURITIES 또는 명시적으로 덮어쓴 CARD 중 최종 선택 한 개의 selected-track evidence와 runtime 결과에서 expected와 actual이 일치하고 owner evidence가 같은 run/hash 및 보존 XML에 연결되는 경우다. 기본/덮어쓰기 표시만 있고 실행 evidence가 없으면 NOT_RUN이다.
- 틀린 예·반례
- compile 가능성과 Red XML은 아직 증명되지 않는다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- phase 이름·manifest finalState·history hash·exit0 하나를 W25 증거 전체와 같다고 보지 않는다.
- 하지 않는 일
- compile 가능성과 Red XML은 아직 증명되지 않는다; README BOM 허용 문구보다 runtime 무 BOM 규칙이 우선한다; reference와 learner root는 서로 달라야 한다; 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다; 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
- 다음 연결
- 다음 조각 또는 F10 evidence 판정으로 상태를 넘긴다.
실행 순서 — raw hash만 검증
-
StarterVerified가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 Prepared 이후 learner가 직접 입력한 선택 트랙 starter hash와 소유권을 확인하되 새 test 실행이 없음을 확인한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘README BOM 허용 문구보다 runtime 무 BOM 규칙이 우선한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 StarterVerified와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 08 / 13
실제 값 따라가기
같은 입력값이 어느 줄을 지나 어떤 결과가 되는지 추적합니다.
| 순서 | 들어온 값 | 코드가 하는 일 | 나온 값·상태 | 경계 |
|---|---|---|---|---|
| 입력 | Prepared | source 계약에 대입 | F10 실행/설명 시작 상태 | compile 가능성과 Red XML은 아직 증명되지 않는다 |
| 검증 | StarterVerified | expected와 actual 또는 형식 대조 | 통과 또는 첫 mismatch | README BOM 허용 문구보다 runtime 무 BOM 규칙이 우선한다 |
| 증거 | runtime_claim=false | marker·hash·row를 같은 run에 연결 | 범위가 적힌 evidence 후보 | 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다 |
실제 값 — raw hash만 검증
-
authoredTarget가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 Prepared 이후 learner가 직접 입력한 선택 트랙 starter hash와 소유권을 확인하되 새 test 실행이 없음을 확인한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘reference와 learner root는 서로 달라야 한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 authoredTarget와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 09 / 13
Gradle·JUnit XML·PowerShell·SQL 내부에서 벌어지는 일
세 test phase, XML bytes archive, Review, 별도 Q41, USER_ATTESTED sealed 결과의 owner와 증명 범위를 구분합니다.
W25-D2-verify-starter.ps1 bytes와 track·phase·hash 계약을 읽는다.
SECURITIES 기본 선택과 파일 존재·phase 이름만으로 runtime Green을 주장할 수 없다. 실제 selected-track evidence와 실행 결과는 별도다.RecordRed·RecordGreen·Cumulative에서만 native exit와 exact JUnit XML을 만든다.
compile 가능성과 Red XML은 아직 증명되지 않는다XML bytes를 고유 파일로 보존하고 history hash와 묶은 뒤, Review는 기존 CumulativeGreen만 인용한다. Q41은 별도 PostgreSQL evidence, sealed official status는 user-attested evidence로 남긴다.
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다첫 실패 경계 — raw hash만 검증
-
canonical/raw SHA-256가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 Prepared 이후 learner가 직접 입력한 선택 트랙 starter hash와 소유권을 확인하되 새 test 실행이 없음을 확인한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 canonical/raw SHA-256와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 10 / 13
흔한 착각과 틀린 예
그럴듯하지만 틀린 해석을 반례로 고칩니다.
❌ Prepare·VerifyStarter·VerifySolution·Review도 Gradle을 실행해 Green을 만든다.
왜 틀리나 runtime에서 test 실행을 소유하는 phase는 RecordRed·RecordGreen·Cumulative뿐이다.
바르게 읽기 각 phase history의 execution 유무와 mode를 직접 확인한다.
반례 VerifySolution은 solution hash만 검증하므로 새 JUnit XML이 없어야 정상이다.
❌ 기본 트랙이 SECURITIES이므로 CARD도 함께 실행해도 되고, 기본 배지만으로 runtime 선택·실행 증거가 완성된다.
왜 틀리나 W25 계약은 실제 사용자 근거가 있는 선택 트랙 하나와 반대 트랙 leak 부재를 요구한다.
바르게 읽기 기본 선택은 SECURITIES(증권)이며 명시적 CARD 선택은 덮어쓰기다. 실행 전 최종 선택 한 개를 selected-track.csv·근거·state에 같은 값으로 고정한다.
반례 SECURITIES 기본 배지만 보고 test 실행을 주장하거나 두 트랙 test가 함께 보이면 선택 경계를 위반한다.
❌ progressive_contract Green이면 manifest의 finalState 10_000도 증명된다.
왜 틀리나 packaged test는 1_000에서 300을 처리한 700/300만 assert한다.
바르게 읽기 10_000 finalState는 별도 learner test 또는 사람이 결박한 evidence로 증명한다.
반례 runtime은 domainContract.finalState 문자열을 parse하거나 assert하지 않는다.
❌ history에 XML SHA가 있으니 Red·Green·Cumulative XML 원본이 모두 보존됐다.
왜 틀리나 다음 cleanTest가 build/test-results의 이전 XML을 덮어쓰며 state는 bytes를 복사하지 않는다.
바르게 읽기 각 phase 직후 고유 evidence 경로로 원자 복사하고 hash를 history와 대조한다.
반례 RecordGreen 뒤에는 Red XML 경로가 사라질 수 있다.
❌ Review가 새 test를 실행해 CumulativeGreen을 다시 만들고 Q41·sealed official 결과까지 자동 확인한다.
왜 틀리나 Review는 기존 CumulativeGreen을 전제로 review entry와 leak check만 기록한다. Q41은 별도 PostgreSQL 과제이고 sealed official status는 user-attested다.
바르게 읽기 Review에서는 reviewedPhase와 history 증가만 보고, Q41 native evidence와 USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED sealed evidence를 별도로 판정한다.
반례 Review 뒤 phase는 여전히 CumulativeGreen이고 새 execution/XML·Q41 transcript·official login verification이 생기지 않는다.
STEP 11 / 13
이 코드가 보장하지 않는 것
선택 미결정·10_000 finalState·XML 보존·Review/Q41/sealed official truth처럼 이 코드가 책임지지 않는 일을 분리합니다.
compile 가능성과 Red XML은 아직 증명되지 않는다
이 책임을 맡는 곳: runtime GateREADME BOM 허용 문구보다 runtime 무 BOM 규칙이 우선한다
이 책임을 맡는 곳: external/human reviewreference와 learner root는 서로 달라야 한다
이 책임을 맡는 곳: release manifest기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
이 책임을 맡는 곳: 운영 환경증명하지 않는 범위 — raw hash만 검증
-
runtime_claim=false가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 Prepared 이후 learner가 직접 입력한 선택 트랙 starter hash와 소유권을 확인하되 새 test 실행이 없음을 확인한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 runtime_claim=false와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 12 / 13
직접 다시 써보기
뜻 → 조각 → 전체 코드 순서로 다시 씁니다.
1단계 · 뜻부터 복원
- Prepared 이후 learner가 직접 입력한 선택 트랙 starter hash와 소유권을 확인하되 새 test 실행이 없음을 확인한다.
- 핵심 값은 Prepared, StarterVerified, authoredTarget, canonical/raw SHA-256, runtime_claim=false다.
2단계 · 코드 조각 재조립
- 1. starter canonical/raw hash만 검증하고 Gradle은 실행하지 않는 phase다
- 2. 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다
- 3. PowerShell 오류를 계속 진행하지 않고 중단시키는 기본 정책을 둔다
- 4. 입력 경로를 실제 절대 경로로 확인한다
- 5. 입력 경로를 실제 절대 경로로 확인한다
- 6. 조건·반복·함수의 실행 block을 연다
- 7. 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다
- 8. 앞에서 연 block 또는 호출 범위를 닫는다
3단계 · 파일 전체 다시 쓰기
illustrative/powershell/W25-D2-verify-starter.ps1을 새 파일에 다시 쓰고 expected·actual·실패·cleanup·비범위를 주석으로 표시한다.
자가 점검
- 비어 있지 않은 모든 source 줄을 한 번씩 읽었나?
- 기본 트랙을 SECURITIES(증권) 하나로 두고 기본 선택·selected-track evidence·runtime Green을 서로 분리했나?
- Review·Q41·USER_ATTESTED sealed 상태를 자동 성공으로 꾸미지 않았나?
- XML bytes archive와 첫 실패·cleanup 책임을 설명할 수 있나?
STEP 13 / 13
전체 원본 source
감사로 고정한 전체 source를 가감 없이 확인합니다.
학습용 예시 전체 확인하기 · 정본 답안 아님 · NOT_RUN
# W25 PDF p8-p17의 VerifyStarter 흐름을 정리한 학습용 예시다.
# 이 phase는 starter bytes/hash와 leak 경계를 검증하지만 Gradle test를 실행하지 않는다.
$ErrorActionPreference = 'Stop'
$ReferenceRoot = (Resolve-Path -LiteralPath $env:FINANCIAL_IT_REFERENCE_ROOT).Path
$LearnerRoot = (Resolve-Path -LiteralPath $env:FINANCIAL_IT_LEARNER_ROOT).Path
if ([string]::Equals($ReferenceRoot, $LearnerRoot, [StringComparison]::OrdinalIgnoreCase)) {
throw 'reference and learner roots must be different'
}
$Before = Get-Content -Raw -LiteralPath (Join-Path $LearnerRoot '.track-learning-stage.json') | ConvertFrom-Json
if ($Before.week -ne 25 -or $Before.phase -cne 'Prepared') { throw 'VerifyStarter requires Prepared' }
$Runner = Join-Path $ReferenceRoot 'scripts\apply-track-learning-stage.ps1'
& powershell.exe -NoProfile -ExecutionPolicy Bypass -File $Runner `
-ReferenceRoot $ReferenceRoot -LearnerRoot $LearnerRoot -Week 25 -Phase VerifyStarter -TimeoutSeconds 1200
if ($LASTEXITCODE -ne 0) { throw "W25 VerifyStarter native exit=$LASTEXITCODE" }
$StatePath = Join-Path $LearnerRoot '.track-learning-stage.json'
$State = Get-Content -Raw -LiteralPath $StatePath | ConvertFrom-Json
$Entry = @($State.history)[-1]
if ($State.phase -cne 'StarterVerified' -or $Entry.phase -cne 'VerifyStarter') {
throw 'W25 VerifyStarter state mismatch'
}
if ($null -eq $Entry.authoredTarget -or $null -ne $Entry.execution) {
throw 'VerifyStarter must record authoredTarget without execution evidence'
}
$Hash = (Get-FileHash -LiteralPath $StatePath -Algorithm SHA256).Hash.ToLowerInvariant()
"W25_STARTER_HASH_VERIFIED phase=StarterVerified runtime_claim=false state_sha256=$Hash"
11D3 RecordRed — exact one-test Red와 XML archive
illustrative/powershell/W25-D3-record-red.ps1
학습용 예시 · W25 phase wrapper · 정본 답안 아님 · 로컬 미실행 · 학습용 예시 · 정본 답안 아님 · NOT_RUN · W25-F1134줄 연결34줄 번역3 chunks
D3 RecordRed — exact one-test Red와 XML archive
illustrative/powershell/W25-D3-record-red.ps1
학습용 예시 · W25 phase wrapper · 정본 답안 아님 · 로컬 미실행 · 학습용 예시 · 정본 답안 아님 · NOT_RUN · W25-F11STEP 01 / 13
오늘 이 코드에서 해결할 문제
무엇을 이해해야 하는지 질문부터 잡습니다.
native nonzero·tests=1·failure+error=1·skip=0·exact method·redMarker를 함께 확인하고 다음 cleanTest 전에 XML bytes를 보존한다.
- LearnerRed은 어느 source와 실제 결과에서 확인해야 할까?
- 첫 실패를 만드는 조건과 fail-closed 지점은 어디일까?
- 왜 ‘compile error는 XML과 marker가 없어 올바른 Red가 아니다’를 별도 경계로 남겨야 할까?
LearnerRednativeExit≠0tests=1failures+errors=1red-exact.xml왜 필요한가 — D3 RecordRed — exact one-test Red와 XML archive
-
LearnerRed가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 native nonzero·tests=1·failure+error=1·skip=0·exact method·redMarker를 함께 확인하고 다음 cleanTest 전에 XML bytes를 보존한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘compile error는 XML과 marker가 없어 올바른 Red가 아니다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 LearnerRed와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 02 / 13
아주 짧게: 이 코드는 왜 필요할까?
웹소설 대신 이 코드가 필요한 이유만 두 문단으로 쉽게 봅니다.
사용자의 기본 선택에 따라 이 HTML은 SECURITIES(증권)을 주 트랙으로 읽는다. CARD는 비교용이며 명시적으로 고르면 기본값을 덮어쓸 수 있다. 실제 실행은 최종 선택 한 개를 selected-track.csv·근거·state에 같은 값으로 기록하고 reference와 learner 폴더를 분리한 뒤에만 시작한다. 이 HTML 자체는 Gradle/JUnit을 실행하지 않아 NOT_RUN 상태다.
한 통장만 골라 빨강에서 초록까지 증명하는 일주일
이 파일은 native nonzero·tests=1·failure+error=1·skip=0·exact method·redMarker를 함께 확인하고 다음 cleanTest 전에 XML bytes를 보존한다. 눈으로 읽을 때는 각 줄을 검수표 한 칸처럼 보고, 입력과 다음 상태를 놓치지 않는다.
마지막 도장은 hash 확인, 세 test phase의 실제 JUnit 실행, XML bytes archive, 사람 review를 서로 구분한 뒤에만 찍는다. Review는 새 test가 아니며 Q41은 stage runtime 밖의 별도 NOT_RUN 과제, sealed official status는 USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED다. 특히 compile error는 XML과 marker가 없어 올바른 Red가 아니다
딱 여기까지만 비유와 SECURITIES 기본 배지는 실제 selected-track 근거, Gradle/JUnit 실행, XML bytes 보존, 사람 review, Q41 실행, sealed official 확인을 대신하지 않는다.
STEP 03 / 13
초등학생도 이해하는 설명
생활 비유와 실제 코드의 경계를 함께 확인합니다.
값 1: LearnerRed
이 파일에서 계속 확인할 고정 단서가 LearnerRed다.
- 코드 연결
F11 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- compile error는 XML과 marker가 없어 올바른 Red가 아니다
값 2: nativeExit≠0
이 파일에서 계속 확인할 고정 단서가 nativeExit≠0다.
- 코드 연결
F11 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- history xmlSha256은 XML bytes 보관을 대신하지 않는다
값 3: tests=1
이 파일에서 계속 확인할 고정 단서가 tests=1다.
- 코드 연결
F11 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- reference와 learner root는 서로 달라야 한다
값 4: failures+errors=1
이 파일에서 계속 확인할 고정 단서가 failures+errors=1다.
- 코드 연결
F11 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
값 5: red-exact.xml
이 파일에서 계속 확인할 고정 단서가 red-exact.xml다.
- 코드 연결
F11 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
STEP 04 / 13
비유 ↔ 코드 전체 연결표
감사 규칙상 연결 대상인 원본 34줄을 빠짐없이 연결합니다.
| 줄 | 정확한 원본 줄 | STARRY 비유 | 실제 뜻·입력·결과·한계 |
|---|---|---|---|
| 1줄F11-L01 | # W25 PDF p18-p22의 exact one-test Red 흐름을 정리한 학습용 예시다. |
출고표 1번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다.
|
| 2줄F11-L02 | # native nonzero exit, |
출고표 2번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다.
|
| 3줄F11-L03 | $ErrorActionPreference = |
출고표 3번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 PowerShell 오류를 계속 진행하지 않고 중단시키는 기본 정책을 둔다.
|
| 4줄F11-L04 | $ReferenceRoot = |
출고표 4번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 입력 경로를 실제 절대 경로로 확인한다.
|
| 5줄F11-L05 | $LearnerRoot = |
출고표 5번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 입력 경로를 실제 절대 경로로 확인한다.
|
| 6줄F11-L06 | if ( |
출고표 6번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 조건·반복·함수의 실행 block을 연다.
|
| 7줄F11-L07 | throw 'reference and learner roots must be different' |
출고표 7번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 8줄F11-L08 | } |
출고표 8번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 10줄F11-L10 | $Verifier = |
출고표 10번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 11줄F11-L11 | & powershell. |
출고표 11번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W25-D3-record-red.ps1의 다음 검증 또는 설명 단계를 구성한다.
|
| 12줄F11-L12 | -ReferenceRoot $ReferenceRoot -LearnerRoot $LearnerRoot -Week 25 -Phase RecordRed -TimeoutSeconds 1200 |
출고표 12번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 선택 트랙 test 하나의 의도한 실패와 Red marker를 기록하는 phase다.
|
| 13줄F11-L13 | if ( |
출고표 13번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 선택 트랙 test 하나의 의도한 실패와 Red marker를 기록하는 phase다.
|
| 15줄F11-L15 | $State = |
출고표 15번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 JSON text를 필드로 접근 가능한 PowerShell object로 바꾼다.
|
| 16줄F11-L16 | $Entry = |
출고표 16번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 17줄F11-L17 | $Suites = |
출고표 17번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 18줄F11-L18 | if ( |
출고표 18번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 19줄F11-L19 | if ( |
출고표 19번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 20줄F11-L20 | $Suite = |
출고표 20번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 21줄F11-L21 | if ( |
출고표 21번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 조건·반복·함수의 실행 block을 연다.
|
| 22줄F11-L22 | throw 'Red XML must be tests= |
출고표 22번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 23줄F11-L23 | } |
출고표 23번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 24줄F11-L24 | $Marker = |
출고표 24번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 25줄F11-L25 | $Log = |
출고표 25번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 26줄F11-L26 | if ( |
출고표 26번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 27줄F11-L27 | $Xml = |
출고표 27번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 28줄F11-L28 | $ArchiveDir = |
출고표 28번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 29줄F11-L29 | New-Item -ItemType Directory -Force -Path $ArchiveDir | Out-Null |
출고표 29번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 Markdown 표 또는 PowerShell pipeline에서 값을 열이나 다음 명령으로 연결한다.
|
| 30줄F11-L30 | $Archive = |
출고표 30번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 덮어쓰기 전에 Red JUnit XML bytes를 고유 evidence 경로로 보존한다.
|
| 31줄F11-L31 | $Tmp = |
출고표 31번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 32줄F11-L32 | Copy-Item -LiteralPath $Xml -Destination $Tmp -Force |
출고표 32번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W25-D3-record-red.ps1의 다음 검증 또는 설명 단계를 구성한다.
|
| 33줄F11-L33 | $ArchiveHash = |
출고표 33번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 현재 bytes를 64자리 digest로 evidence에 결박한다.
|
| 34줄F11-L34 | if ( |
출고표 34번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 현재 bytes를 64자리 digest로 evidence에 결박한다.
|
| 35줄F11-L35 | Move-Item -LiteralPath $Tmp -Destination $Archive -Force |
출고표 35번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W25-D3-record-red.ps1의 다음 검증 또는 설명 단계를 구성한다.
|
| 36줄F11-L36 | "W25_EXACT_RED_VERIFIED track= |
출고표 36번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 현재 bytes를 64자리 digest로 evidence에 결박한다.
|
STEP 05 / 13
원본 코드 조각
원본을 3개 의미 조각으로 나누어 그대로 확인합니다.
파일을 한꺼번에 외우지 않고 실행 의미가 이어지는 작은 조각으로 봅니다. 아래 코드는 prompt·fixture·가정을 밝힌 학습용 예시 source이며, 제공 정본 답안이나 실행 결과가 아닌 NOT_RUN 자료입니다.
# W25 PDF p18-p22의 exact one-test Red 흐름을 정리한 학습용 예시다.
# native nonzero exit, 단일 JUnit 실패, 선택 트랙 redMarker가 함께 있어야 Red다.
$ErrorActionPreference = 'Stop'
$ReferenceRoot = (Resolve-Path -LiteralPath $env:FINANCIAL_IT_REFERENCE_ROOT).Path
$LearnerRoot = (Resolve-Path -LiteralPath $env:FINANCIAL_IT_LEARNER_ROOT).Path
if ([string]::Equals($ReferenceRoot, $LearnerRoot, [StringComparison]::OrdinalIgnoreCase)) {
throw 'reference and learner roots must be different'
}
$Verifier = Join-Path $ReferenceRoot 'scripts\verify-track-learner-proof.ps1'
& powershell.exe -NoProfile -ExecutionPolicy Bypass -File $Verifier `
-ReferenceRoot $ReferenceRoot -LearnerRoot $LearnerRoot -Week 25 -Phase RecordRed -TimeoutSeconds 1200
if ($LASTEXITCODE -ne 0) { throw "W25 RecordRed wrapper exit=$LASTEXITCODE" }
$State = Get-Content -Raw -LiteralPath (Join-Path $LearnerRoot '.track-learning-stage.json') | ConvertFrom-Json
$Entry = @($State.history)[-1]
$Suites = @($Entry.execution.suites)
if ($State.phase -cne 'LearnerRed' -or $Entry.execution.mode -cne 'Red') { throw 'LearnerRed state mismatch' }
if ($Entry.execution.nativeExit -eq 0 -or $Suites.Count -ne 1) { throw 'Red must have native nonzero exit and one suite' }
$Suite = $Suites[0]
if ($Suite.tests -ne 1 -or ($Suite.failures + $Suite.errors) -ne 1 -or $Suite.skipped -ne 0) {
throw 'Red XML must be tests=1, failures+errors=1, skipped=0'
}
$Marker = if ($State.track -ceq 'SECURITIES') { 'W25_SECURITIES_RED_EXPECTED' } else { 'W25_CARD_RED_EXPECTED' }
$Log = Get-Content -Raw -LiteralPath (Join-Path $LearnerRoot $Entry.execution.log)
if ($Log -cnotmatch [regex]::Escape($Marker)) { throw "exact Red marker missing: $Marker" }
$Xml = Join-Path $LearnerRoot ("build\test-results\test\TEST-{0}.xml" -f $Suite.selector)
$ArchiveDir = Join-Path $LearnerRoot ("evidence\w25\{0}" -f $State.track.ToLowerInvariant())
New-Item -ItemType Directory -Force -Path $ArchiveDir | Out-Null
$Archive = Join-Path $ArchiveDir 'red-exact.xml'
$Tmp = "$Archive.tmp"
Copy-Item -LiteralPath $Xml -Destination $Tmp -Force
$ArchiveHash = (Get-FileHash -LiteralPath $Tmp -Algorithm SHA256).Hash.ToLowerInvariant()
if ($ArchiveHash -cne $Suite.xmlSha256) { throw 'archived Red XML hash differs from runtime history' }
Move-Item -LiteralPath $Tmp -Destination $Archive -Force
"W25_EXACT_RED_VERIFIED track=$($State.track) tests=1 failures_or_errors=1 native_exit=$($Entry.execution.nativeExit) archived_xml_sha256=$ArchiveHash"
STEP 06 / 13
코드 한 줄씩 한국어로 번역
비어 있지 않은 34줄을 모두 한국어로 옮깁니다.
비어 있지 않은 원본 줄은 하나도 생략하지 않습니다.
| 줄 | 원본 | 한국어 번역 |
|---|---|---|
| 1 | # W25 PDF p18-p22의 exact one-test Red 흐름을 정리한 학습용 예시다. | 문서 의미: 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다. |
| 2 | # native nonzero exit, 단일 JUnit 실패, 선택 트랙 redMarker가 함께 있어야 Red다. | 문서 의미: 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다. |
| 3 | $ErrorActionPreference = 'Stop' | 실행 의미: PowerShell 오류를 계속 진행하지 않고 중단시키는 기본 정책을 둔다. |
| 4 | $ReferenceRoot = (Resolve-Path -LiteralPath $env:FINANCIAL_IT_REFERENCE_ROOT).Path | 실행 의미: 입력 경로를 실제 절대 경로로 확인한다. |
| 5 | $LearnerRoot = (Resolve-Path -LiteralPath $env:FINANCIAL_IT_LEARNER_ROOT).Path | 실행 의미: 입력 경로를 실제 절대 경로로 확인한다. |
| 6 | if ([string]::Equals($ReferenceRoot, $LearnerRoot, [StringComparison]::OrdinalIgnoreCase)) { | 실행 의미: 조건·반복·함수의 실행 block을 연다. |
| 7 | throw 'reference and learner roots must be different' | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 8 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 10 | $Verifier = Join-Path $ReferenceRoot 'scripts\verify-track-learner-proof.ps1' | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 11 | & powershell.exe -NoProfile -ExecutionPolicy Bypass -File $Verifier ` | 실행 의미: W25-D3-record-red.ps1의 다음 검증 또는 설명 단계를 구성한다. |
| 12 | -ReferenceRoot $ReferenceRoot -LearnerRoot $LearnerRoot -Week 25 -Phase RecordRed -TimeoutSeconds 1200 | 실행 의미: 선택 트랙 test 하나의 의도한 실패와 Red marker를 기록하는 phase다. |
| 13 | if ($LASTEXITCODE -ne 0) { throw "W25 RecordRed wrapper exit=$LASTEXITCODE" } | 실행 의미: 선택 트랙 test 하나의 의도한 실패와 Red marker를 기록하는 phase다. |
| 15 | $State = Get-Content -Raw -LiteralPath (Join-Path $LearnerRoot '.track-learning-stage.json') | ConvertFrom-Json | 실행 의미: JSON text를 필드로 접근 가능한 PowerShell object로 바꾼다. |
| 16 | $Entry = @($State.history)[-1] | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 17 | $Suites = @($Entry.execution.suites) | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 18 | if ($State.phase -cne 'LearnerRed' -or $Entry.execution.mode -cne 'Red') { throw 'LearnerRed state mismatch' } | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 19 | if ($Entry.execution.nativeExit -eq 0 -or $Suites.Count -ne 1) { throw 'Red must have native nonzero exit and one suite' } | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 20 | $Suite = $Suites[0] | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 21 | if ($Suite.tests -ne 1 -or ($Suite.failures + $Suite.errors) -ne 1 -or $Suite.skipped -ne 0) { | 실행 의미: 조건·반복·함수의 실행 block을 연다. |
| 22 | throw 'Red XML must be tests=1, failures+errors=1, skipped=0' | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 23 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 24 | $Marker = if ($State.track -ceq 'SECURITIES') { 'W25_SECURITIES_RED_EXPECTED' } else { 'W25_CARD_RED_EXPECTED' } | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 25 | $Log = Get-Content -Raw -LiteralPath (Join-Path $LearnerRoot $Entry.execution.log) | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 26 | if ($Log -cnotmatch [regex]::Escape($Marker)) { throw "exact Red marker missing: $Marker" } | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 27 | $Xml = Join-Path $LearnerRoot ("build\test-results\test\TEST-{0}.xml" -f $Suite.selector) | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 28 | $ArchiveDir = Join-Path $LearnerRoot ("evidence\w25\{0}" -f $State.track.ToLowerInvariant()) | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 29 | New-Item -ItemType Directory -Force -Path $ArchiveDir | Out-Null | 실행 의미: Markdown 표 또는 PowerShell pipeline에서 값을 열이나 다음 명령으로 연결한다. |
| 30 | $Archive = Join-Path $ArchiveDir 'red-exact.xml' | 실행 의미: 덮어쓰기 전에 Red JUnit XML bytes를 고유 evidence 경로로 보존한다. |
| 31 | $Tmp = "$Archive.tmp" | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 32 | Copy-Item -LiteralPath $Xml -Destination $Tmp -Force | 실행 의미: W25-D3-record-red.ps1의 다음 검증 또는 설명 단계를 구성한다. |
| 33 | $ArchiveHash = (Get-FileHash -LiteralPath $Tmp -Algorithm SHA256).Hash.ToLowerInvariant() | 실행 의미: 현재 bytes를 64자리 digest로 evidence에 결박한다. |
| 34 | if ($ArchiveHash -cne $Suite.xmlSha256) { throw 'archived Red XML hash differs from runtime history' } | 실행 의미: 현재 bytes를 64자리 digest로 evidence에 결박한다. |
| 35 | Move-Item -LiteralPath $Tmp -Destination $Archive -Force | 실행 의미: W25-D3-record-red.ps1의 다음 검증 또는 설명 단계를 구성한다. |
| 36 | "W25_EXACT_RED_VERIFIED track=$($State.track) tests=1 failures_or_errors=1 native_exit=$($Entry.execution.nativeExit) archived_xml_sha256=$ArchiveHash" | 실행 의미: 현재 bytes를 64자리 digest로 evidence에 결박한다. |
STEP 07 / 13
기존 수준의 한 줄 읽기·문법 해부
쉬운 설명 다음에 문법과 실행 순서를 정밀하게 읽습니다.
한 줄로 읽기D3 RecordRed — exact one-test Red와 XML archive는 native nonzero·tests=1·failure+error=1·skip=0·exact method·redMarker를 함께 확인하고 다음 cleanTest 전에 XML bytes를 보존한다.
문법 해부
- .ps1 문법에서 선언·조건·pipeline·block 경계를 먼저 나눈다.
- manifest의 finalState와 packaged progressive test의 1_000→700/300 oracle을 서로 다른 계약으로 읽는다.
- phase state·native exit·JUnit XML hash·보존된 XML bytes·사람 판정·USER_ATTESTED external status를 서로 대체하지 않는다.
실행 순서
- 기본 트랙은 SECURITIES(증권)이며, 명시적 CARD 선택은 기본값을 덮어쓴다. 실제 실행 전 최종 선택 한 개를 selected-track.csv·근거·state에 같은 값으로 기록하고 서로 다른 reference/learner root를 확인한다.
- Prepare→VerifyStarter→RecordRed→VerifySolution→RecordGreen→Cumulative→Review 순서를 지킨다.
- test를 소유한 세 phase에서만 native exit와 exact JUnit XML 수치를 판정한다.
- 다음 cleanTest 전에 XML bytes를 고유 경로에 보존하고 runtime history hash와 다시 묶는다. Review·Q41·sealed official evidence는 각자의 별도 owner와 검증 수준으로 남긴다.
W25 조각별 정밀 해설
F11-C01 · 원문 1–12줄
- 문법 해부
- .ps1 문법으로 1–12줄의 선언·조건·phase·assert block을 나눈다.
- 실제 값 추적
- LearnerRed, nativeExit≠0, tests=1를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- 기본 SECURITIES 또는 명시적으로 덮어쓴 CARD 중 최종 선택 한 개의 selected-track evidence와 runtime 결과에서 expected와 actual이 일치하고 owner evidence가 같은 run/hash 및 보존 XML에 연결되는 경우다. 기본/덮어쓰기 표시만 있고 실행 evidence가 없으면 NOT_RUN이다.
- 틀린 예·반례
- compile error는 XML과 marker가 없어 올바른 Red가 아니다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- phase 이름·manifest finalState·history hash·exit0 하나를 W25 증거 전체와 같다고 보지 않는다.
- 하지 않는 일
- compile error는 XML과 marker가 없어 올바른 Red가 아니다; history xmlSha256은 XML bytes 보관을 대신하지 않는다; reference와 learner root는 서로 달라야 한다; 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다; 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
- 다음 연결
- 다음 조각 또는 F11 evidence 판정으로 상태를 넘긴다.
F11-C02 · 원문 13–24줄
- 문법 해부
- .ps1 문법으로 13–24줄의 선언·조건·phase·assert block을 나눈다.
- 실제 값 추적
- LearnerRed, nativeExit≠0, tests=1를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- 기본 SECURITIES 또는 명시적으로 덮어쓴 CARD 중 최종 선택 한 개의 selected-track evidence와 runtime 결과에서 expected와 actual이 일치하고 owner evidence가 같은 run/hash 및 보존 XML에 연결되는 경우다. 기본/덮어쓰기 표시만 있고 실행 evidence가 없으면 NOT_RUN이다.
- 틀린 예·반례
- compile error는 XML과 marker가 없어 올바른 Red가 아니다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- phase 이름·manifest finalState·history hash·exit0 하나를 W25 증거 전체와 같다고 보지 않는다.
- 하지 않는 일
- compile error는 XML과 marker가 없어 올바른 Red가 아니다; history xmlSha256은 XML bytes 보관을 대신하지 않는다; reference와 learner root는 서로 달라야 한다; 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다; 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
- 다음 연결
- 다음 조각 또는 F11 evidence 판정으로 상태를 넘긴다.
F11-C03 · 원문 25–36줄
- 문법 해부
- .ps1 문법으로 25–36줄의 선언·조건·phase·assert block을 나눈다.
- 실제 값 추적
- LearnerRed, nativeExit≠0, tests=1를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- 기본 SECURITIES 또는 명시적으로 덮어쓴 CARD 중 최종 선택 한 개의 selected-track evidence와 runtime 결과에서 expected와 actual이 일치하고 owner evidence가 같은 run/hash 및 보존 XML에 연결되는 경우다. 기본/덮어쓰기 표시만 있고 실행 evidence가 없으면 NOT_RUN이다.
- 틀린 예·반례
- compile error는 XML과 marker가 없어 올바른 Red가 아니다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- phase 이름·manifest finalState·history hash·exit0 하나를 W25 증거 전체와 같다고 보지 않는다.
- 하지 않는 일
- compile error는 XML과 marker가 없어 올바른 Red가 아니다; history xmlSha256은 XML bytes 보관을 대신하지 않는다; reference와 learner root는 서로 달라야 한다; 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다; 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
- 다음 연결
- 다음 조각 또는 F11 evidence 판정으로 상태를 넘긴다.
실행 순서 — D3 RecordRed — exact one-test Red와 XML archive
-
nativeExit≠0가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 native nonzero·tests=1·failure+error=1·skip=0·exact method·redMarker를 함께 확인하고 다음 cleanTest 전에 XML bytes를 보존한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘history xmlSha256은 XML bytes 보관을 대신하지 않는다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 nativeExit≠0와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 08 / 13
실제 값 따라가기
같은 입력값이 어느 줄을 지나 어떤 결과가 되는지 추적합니다.
| 순서 | 들어온 값 | 코드가 하는 일 | 나온 값·상태 | 경계 |
|---|---|---|---|---|
| 입력 | LearnerRed | source 계약에 대입 | F11 실행/설명 시작 상태 | compile error는 XML과 marker가 없어 올바른 Red가 아니다 |
| 검증 | nativeExit≠0 | expected와 actual 또는 형식 대조 | 통과 또는 첫 mismatch | history xmlSha256은 XML bytes 보관을 대신하지 않는다 |
| 증거 | red-exact.xml | marker·hash·row를 같은 run에 연결 | 범위가 적힌 evidence 후보 | 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다 |
실제 값 — D3 RecordRed — exact one-test Red와 XML archive
-
tests=1가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 native nonzero·tests=1·failure+error=1·skip=0·exact method·redMarker를 함께 확인하고 다음 cleanTest 전에 XML bytes를 보존한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘reference와 learner root는 서로 달라야 한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 tests=1와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 09 / 13
Gradle·JUnit XML·PowerShell·SQL 내부에서 벌어지는 일
세 test phase, XML bytes archive, Review, 별도 Q41, USER_ATTESTED sealed 결과의 owner와 증명 범위를 구분합니다.
W25-D3-record-red.ps1 bytes와 track·phase·hash 계약을 읽는다.
SECURITIES 기본 선택과 파일 존재·phase 이름만으로 runtime Green을 주장할 수 없다. 실제 selected-track evidence와 실행 결과는 별도다.RecordRed·RecordGreen·Cumulative에서만 native exit와 exact JUnit XML을 만든다.
compile error는 XML과 marker가 없어 올바른 Red가 아니다XML bytes를 고유 파일로 보존하고 history hash와 묶은 뒤, Review는 기존 CumulativeGreen만 인용한다. Q41은 별도 PostgreSQL evidence, sealed official status는 user-attested evidence로 남긴다.
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다첫 실패 경계 — D3 RecordRed — exact one-test Red와 XML archive
-
failures+errors=1가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 native nonzero·tests=1·failure+error=1·skip=0·exact method·redMarker를 함께 확인하고 다음 cleanTest 전에 XML bytes를 보존한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 failures+errors=1와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 10 / 13
흔한 착각과 틀린 예
그럴듯하지만 틀린 해석을 반례로 고칩니다.
❌ Prepare·VerifyStarter·VerifySolution·Review도 Gradle을 실행해 Green을 만든다.
왜 틀리나 runtime에서 test 실행을 소유하는 phase는 RecordRed·RecordGreen·Cumulative뿐이다.
바르게 읽기 각 phase history의 execution 유무와 mode를 직접 확인한다.
반례 VerifySolution은 solution hash만 검증하므로 새 JUnit XML이 없어야 정상이다.
❌ 기본 트랙이 SECURITIES이므로 CARD도 함께 실행해도 되고, 기본 배지만으로 runtime 선택·실행 증거가 완성된다.
왜 틀리나 W25 계약은 실제 사용자 근거가 있는 선택 트랙 하나와 반대 트랙 leak 부재를 요구한다.
바르게 읽기 기본 선택은 SECURITIES(증권)이며 명시적 CARD 선택은 덮어쓰기다. 실행 전 최종 선택 한 개를 selected-track.csv·근거·state에 같은 값으로 고정한다.
반례 SECURITIES 기본 배지만 보고 test 실행을 주장하거나 두 트랙 test가 함께 보이면 선택 경계를 위반한다.
❌ progressive_contract Green이면 manifest의 finalState 10_000도 증명된다.
왜 틀리나 packaged test는 1_000에서 300을 처리한 700/300만 assert한다.
바르게 읽기 10_000 finalState는 별도 learner test 또는 사람이 결박한 evidence로 증명한다.
반례 runtime은 domainContract.finalState 문자열을 parse하거나 assert하지 않는다.
❌ history에 XML SHA가 있으니 Red·Green·Cumulative XML 원본이 모두 보존됐다.
왜 틀리나 다음 cleanTest가 build/test-results의 이전 XML을 덮어쓰며 state는 bytes를 복사하지 않는다.
바르게 읽기 각 phase 직후 고유 evidence 경로로 원자 복사하고 hash를 history와 대조한다.
반례 RecordGreen 뒤에는 Red XML 경로가 사라질 수 있다.
❌ Review가 새 test를 실행해 CumulativeGreen을 다시 만들고 Q41·sealed official 결과까지 자동 확인한다.
왜 틀리나 Review는 기존 CumulativeGreen을 전제로 review entry와 leak check만 기록한다. Q41은 별도 PostgreSQL 과제이고 sealed official status는 user-attested다.
바르게 읽기 Review에서는 reviewedPhase와 history 증가만 보고, Q41 native evidence와 USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED sealed evidence를 별도로 판정한다.
반례 Review 뒤 phase는 여전히 CumulativeGreen이고 새 execution/XML·Q41 transcript·official login verification이 생기지 않는다.
STEP 11 / 13
이 코드가 보장하지 않는 것
선택 미결정·10_000 finalState·XML 보존·Review/Q41/sealed official truth처럼 이 코드가 책임지지 않는 일을 분리합니다.
compile error는 XML과 marker가 없어 올바른 Red가 아니다
이 책임을 맡는 곳: runtime Gatehistory xmlSha256은 XML bytes 보관을 대신하지 않는다
이 책임을 맡는 곳: external/human reviewreference와 learner root는 서로 달라야 한다
이 책임을 맡는 곳: release manifest기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
이 책임을 맡는 곳: 운영 환경증명하지 않는 범위 — D3 RecordRed — exact one-test Red와 XML archive
-
red-exact.xml가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 native nonzero·tests=1·failure+error=1·skip=0·exact method·redMarker를 함께 확인하고 다음 cleanTest 전에 XML bytes를 보존한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 red-exact.xml와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 12 / 13
직접 다시 써보기
뜻 → 조각 → 전체 코드 순서로 다시 씁니다.
1단계 · 뜻부터 복원
- native nonzero·tests=1·failure+error=1·skip=0·exact method·redMarker를 함께 확인하고 다음 cleanTest 전에 XML bytes를 보존한다.
- 핵심 값은 LearnerRed, nativeExit≠0, tests=1, failures+errors=1, red-exact.xml다.
2단계 · 코드 조각 재조립
- 1. 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다
- 2. 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다
- 3. PowerShell 오류를 계속 진행하지 않고 중단시키는 기본 정책을 둔다
- 4. 입력 경로를 실제 절대 경로로 확인한다
- 5. 입력 경로를 실제 절대 경로로 확인한다
- 6. 조건·반복·함수의 실행 block을 연다
- 7. 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다
- 8. 앞에서 연 block 또는 호출 범위를 닫는다
3단계 · 파일 전체 다시 쓰기
illustrative/powershell/W25-D3-record-red.ps1을 새 파일에 다시 쓰고 expected·actual·실패·cleanup·비범위를 주석으로 표시한다.
자가 점검
- 비어 있지 않은 모든 source 줄을 한 번씩 읽었나?
- 기본 트랙을 SECURITIES(증권) 하나로 두고 기본 선택·selected-track evidence·runtime Green을 서로 분리했나?
- Review·Q41·USER_ATTESTED sealed 상태를 자동 성공으로 꾸미지 않았나?
- XML bytes archive와 첫 실패·cleanup 책임을 설명할 수 있나?
STEP 13 / 13
전체 원본 source
감사로 고정한 전체 source를 가감 없이 확인합니다.
학습용 예시 전체 확인하기 · 정본 답안 아님 · NOT_RUN
# W25 PDF p18-p22의 exact one-test Red 흐름을 정리한 학습용 예시다.
# native nonzero exit, 단일 JUnit 실패, 선택 트랙 redMarker가 함께 있어야 Red다.
$ErrorActionPreference = 'Stop'
$ReferenceRoot = (Resolve-Path -LiteralPath $env:FINANCIAL_IT_REFERENCE_ROOT).Path
$LearnerRoot = (Resolve-Path -LiteralPath $env:FINANCIAL_IT_LEARNER_ROOT).Path
if ([string]::Equals($ReferenceRoot, $LearnerRoot, [StringComparison]::OrdinalIgnoreCase)) {
throw 'reference and learner roots must be different'
}
$Verifier = Join-Path $ReferenceRoot 'scripts\verify-track-learner-proof.ps1'
& powershell.exe -NoProfile -ExecutionPolicy Bypass -File $Verifier `
-ReferenceRoot $ReferenceRoot -LearnerRoot $LearnerRoot -Week 25 -Phase RecordRed -TimeoutSeconds 1200
if ($LASTEXITCODE -ne 0) { throw "W25 RecordRed wrapper exit=$LASTEXITCODE" }
$State = Get-Content -Raw -LiteralPath (Join-Path $LearnerRoot '.track-learning-stage.json') | ConvertFrom-Json
$Entry = @($State.history)[-1]
$Suites = @($Entry.execution.suites)
if ($State.phase -cne 'LearnerRed' -or $Entry.execution.mode -cne 'Red') { throw 'LearnerRed state mismatch' }
if ($Entry.execution.nativeExit -eq 0 -or $Suites.Count -ne 1) { throw 'Red must have native nonzero exit and one suite' }
$Suite = $Suites[0]
if ($Suite.tests -ne 1 -or ($Suite.failures + $Suite.errors) -ne 1 -or $Suite.skipped -ne 0) {
throw 'Red XML must be tests=1, failures+errors=1, skipped=0'
}
$Marker = if ($State.track -ceq 'SECURITIES') { 'W25_SECURITIES_RED_EXPECTED' } else { 'W25_CARD_RED_EXPECTED' }
$Log = Get-Content -Raw -LiteralPath (Join-Path $LearnerRoot $Entry.execution.log)
if ($Log -cnotmatch [regex]::Escape($Marker)) { throw "exact Red marker missing: $Marker" }
$Xml = Join-Path $LearnerRoot ("build\test-results\test\TEST-{0}.xml" -f $Suite.selector)
$ArchiveDir = Join-Path $LearnerRoot ("evidence\w25\{0}" -f $State.track.ToLowerInvariant())
New-Item -ItemType Directory -Force -Path $ArchiveDir | Out-Null
$Archive = Join-Path $ArchiveDir 'red-exact.xml'
$Tmp = "$Archive.tmp"
Copy-Item -LiteralPath $Xml -Destination $Tmp -Force
$ArchiveHash = (Get-FileHash -LiteralPath $Tmp -Algorithm SHA256).Hash.ToLowerInvariant()
if ($ArchiveHash -cne $Suite.xmlSha256) { throw 'archived Red XML hash differs from runtime history' }
Move-Item -LiteralPath $Tmp -Destination $Archive -Force
"W25_EXACT_RED_VERIFIED track=$($State.track) tests=1 failures_or_errors=1 native_exit=$($Entry.execution.nativeExit) archived_xml_sha256=$ArchiveHash"
12SECURITIES solution CashWallet — availableCash 차감 복구
track_learning_stages/securities/w25/solution/src/main/java/com/example/financialcore/securities/CashWallet.java
PDF 전문 정본 · learner solution Java · 정본 · W25-F1256줄 연결56줄 번역6 chunks
SECURITIES solution CashWallet — availableCash 차감 복구
track_learning_stages/securities/w25/solution/src/main/java/com/example/financialcore/securities/CashWallet.java
PDF 전문 정본 · learner solution Java · 정본 · W25-F12STEP 01 / 13
오늘 이 코드에서 해결할 문제
무엇을 이해해야 하는지 질문부터 잡습니다.
reserve에서 availableCash를 amount만큼 차감해 available+reserved 총액 보존을 복구한다.
- availableCash -= amount은 어느 source와 실제 결과에서 확인해야 할까?
- 첫 실패를 만드는 조건과 fail-closed 지점은 어디일까?
- 왜 ‘solution hash만으로 Green은 아니다’를 별도 경계로 남겨야 할까?
availableCash -= amountreservedCash = addExact1_000→700/300nonnegativeLEARNER_AUTHORED after manual entry왜 필요한가 — SECURITIES solution CashWallet — availableCash 차감 복구
-
availableCash -= amount가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 reserve에서 availableCash를 amount만큼 차감해 available+reserved 총액 보존을 복구한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘solution hash만으로 Green은 아니다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 availableCash -= amount와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 02 / 13
아주 짧게: 이 코드는 왜 필요할까?
웹소설 대신 이 코드가 필요한 이유만 두 문단으로 쉽게 봅니다.
사용자의 기본 선택에 따라 이 HTML은 SECURITIES(증권)을 주 트랙으로 읽는다. CARD는 비교용이며 명시적으로 고르면 기본값을 덮어쓸 수 있다. 실제 실행은 최종 선택 한 개를 selected-track.csv·근거·state에 같은 값으로 기록하고 reference와 learner 폴더를 분리한 뒤에만 시작한다. 이 HTML 자체는 Gradle/JUnit을 실행하지 않아 NOT_RUN 상태다.
한 통장만 골라 빨강에서 초록까지 증명하는 일주일
이 파일은 reserve에서 availableCash를 amount만큼 차감해 available+reserved 총액 보존을 복구한다. 눈으로 읽을 때는 각 줄을 검수표 한 칸처럼 보고, 입력과 다음 상태를 놓치지 않는다.
마지막 도장은 hash 확인, 세 test phase의 실제 JUnit 실행, XML bytes archive, 사람 review를 서로 구분한 뒤에만 찍는다. Review는 새 test가 아니며 Q41은 stage runtime 밖의 별도 NOT_RUN 과제, sealed official status는 USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED다. 특히 solution hash만으로 Green은 아니다
딱 여기까지만 비유와 SECURITIES 기본 배지는 실제 selected-track 근거, Gradle/JUnit 실행, XML bytes 보존, 사람 review, Q41 실행, sealed official 확인을 대신하지 않는다.
STEP 03 / 13
초등학생도 이해하는 설명
생활 비유와 실제 코드의 경계를 함께 확인합니다.
값 1: availableCash -= amount
이 파일에서 계속 확인할 고정 단서가 availableCash -= amount다.
- 코드 연결
F12 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- solution hash만으로 Green은 아니다
값 2: reservedCash = addExact
이 파일에서 계속 확인할 고정 단서가 reservedCash = addExact다.
- 코드 연결
F12 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- 0/10_000은 별도 scenario가 필요하다
값 3: 1_000→700/300
이 파일에서 계속 확인할 고정 단서가 1_000→700/300다.
- 코드 연결
F12 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- DB lock·동시 예약은 범위 밖이다
값 4: nonnegative
이 파일에서 계속 확인할 고정 단서가 nonnegative다.
- 코드 연결
F12 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- reference와 learner root는 서로 달라야 한다
값 5: LEARNER_AUTHORED after manual entry
이 파일에서 계속 확인할 고정 단서가 LEARNER_AUTHORED after manual entry다.
- 코드 연결
F12 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
STEP 04 / 13
비유 ↔ 코드 전체 연결표
감사 규칙상 연결 대상인 원본 56줄을 빠짐없이 연결합니다.
| 줄 | 정확한 원본 줄 | STARRY 비유 | 실제 뜻·입력·결과·한계 |
|---|---|---|---|
| 1줄F12-L01 | package com. |
출고표 1번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 3줄F12-L03 | import jakarta. |
출고표 3번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 4줄F12-L04 | import jakarta. |
출고표 4번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 5줄F12-L05 | import jakarta. |
출고표 5번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 6줄F12-L06 | import jakarta. |
출고표 6번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 7줄F12-L07 | import jakarta. |
출고표 7번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 8줄F12-L08 | import jakarta. |
출고표 8번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 9줄F12-L09 | import jakarta. |
출고표 9번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 11줄F12-L11 | @Entity |
출고표 11번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 12줄F12-L12 | @Table( |
출고표 12번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 13줄F12-L13 | public class CashWallet { |
출고표 13번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 조건·반복·함수의 실행 block을 연다.
|
| 14줄F12-L14 | @Id |
출고표 14번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 15줄F12-L15 | @GeneratedValue( |
출고표 15번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 16줄F12-L16 | private Long id; |
출고표 16번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 18줄F12-L18 | @Column( |
출고표 18번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 19줄F12-L19 | private String investorKey; |
출고표 19번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 21줄F12-L21 | @Column( |
출고표 21번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 22줄F12-L22 | private long availableCash; |
출고표 22번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 24줄F12-L24 | @Column( |
출고표 24번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 25줄F12-L25 | private long reservedCash; |
출고표 25번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 27줄F12-L27 | @Version |
출고표 27번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 28줄F12-L28 | private long version; |
출고표 28번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 30줄F12-L30 | protected CashWallet( |
출고표 30번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 32줄F12-L32 | private CashWallet( |
출고표 32번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 조건·반복·함수의 실행 block을 연다.
|
| 33줄F12-L33 | if ( |
출고표 33번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 34줄F12-L34 | if ( |
출고표 34번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 35줄F12-L35 | this. |
출고표 35번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 36줄F12-L36 | this. |
출고표 36번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 37줄F12-L37 | } |
출고표 37번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 39줄F12-L39 | public static CashWallet open( |
출고표 39번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 조건·반복·함수의 실행 block을 연다.
|
| 40줄F12-L40 | return new CashWallet( |
출고표 40번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 41줄F12-L41 | } |
출고표 41번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 43줄F12-L43 | public void reserve( |
출고표 43번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 조건·반복·함수의 실행 block을 연다.
|
| 44줄F12-L44 | if ( |
출고표 44번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 45줄F12-L45 | if ( |
출고표 45번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 46줄F12-L46 | availableCash -= |
출고표 46번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 solution에서 예약액만큼 가용 현금을 실제로 차감한다.
|
| 47줄F12-L47 | reservedCash = |
출고표 47번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 48줄F12-L48 | } |
출고표 48번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 50줄F12-L50 | public void settle( |
출고표 50번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 조건·반복·함수의 실행 block을 연다.
|
| 51줄F12-L51 | if ( |
출고표 51번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 Markdown 표 또는 PowerShell pipeline에서 값을 열이나 다음 명령으로 연결한다.
|
| 52줄F12-L52 | throw new IllegalArgumentException( |
출고표 52번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 53줄F12-L53 | } |
출고표 53번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 54줄F12-L54 | if ( |
출고표 54번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 55줄F12-L55 | reservedCash -= |
출고표 55번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 56줄F12-L56 | availableCash = |
출고표 56번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 57줄F12-L57 | } |
출고표 57번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 59줄F12-L59 | public void releaseReservation( |
출고표 59번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 조건·반복·함수의 실행 block을 연다.
|
| 60줄F12-L60 | if ( |
출고표 60번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 61줄F12-L61 | reservedCash -= |
출고표 61번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 62줄F12-L62 | availableCash = |
출고표 62번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 63줄F12-L63 | } |
출고표 63번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 65줄F12-L65 | public Long getId( |
출고표 65번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 66줄F12-L66 | public String getInvestorKey( |
출고표 66번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 67줄F12-L67 | public long getAvailableCash( |
출고표 67번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 예약 뒤 가용 현금이 700인지 관찰한다.
|
| 68줄F12-L68 | public long getReservedCash( |
출고표 68번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 예약 뒤 예약 현금이 300인지 관찰한다.
|
| 69줄F12-L69 | } |
출고표 69번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
STEP 05 / 13
원본 코드 조각
원본을 6개 의미 조각으로 나누어 그대로 확인합니다.
파일을 한꺼번에 외우지 않고 실행 의미가 이어지는 작은 조각으로 봅니다. 아래 코드는 hash로 고정한 native 정본 source에서 그대로 잘랐습니다.
package com.example.financialcore.securities;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import jakarta.persistence.Version;
@Entity
@Table(name = "securities_cash_wallet")
public class CashWallet {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "investor_key", nullable = false, unique = true, length = 64)
private String investorKey;
@Column(name = "available_cash", nullable = false)
private long availableCash;
@Column(name = "reserved_cash", nullable = false)
private long reservedCash;
@Version
private long version;
protected CashWallet() {}
private CashWallet(String investorKey, long availableCash) {
if (investorKey == null || investorKey.isBlank()) throw new IllegalArgumentException("investorKey");
if (availableCash < 0) throw new IllegalArgumentException("availableCash");
this.investorKey = investorKey;
this.availableCash = availableCash;
}
public static CashWallet open(String investorKey, long availableCash) {
return new CashWallet(investorKey, availableCash);
}
public void reserve(long amount) {
if (amount <= 0) throw new IllegalArgumentException("amount");
if (availableCash < amount) throw new IllegalStateException("INSUFFICIENT_AVAILABLE_CASH");
availableCash -= amount;
reservedCash = Math.addExact(reservedCash, amount);
}
public void settle(long reservedAmount, long executedAmount) {
if (reservedAmount <= 0 || executedAmount <= 0 || executedAmount > reservedAmount) {
throw new IllegalArgumentException("settlement amount");
}
if (reservedCash < reservedAmount) throw new IllegalStateException("RESERVATION_MISMATCH");
reservedCash -= reservedAmount;
availableCash = Math.addExact(availableCash, reservedAmount - executedAmount);
}
public void releaseReservation(long amount) {
if (amount <= 0 || reservedCash < amount) throw new IllegalArgumentException("amount");
reservedCash -= amount;
availableCash = Math.addExact(availableCash, amount);
}
public Long getId() { return id; }
public String getInvestorKey() { return investorKey; }
public long getAvailableCash() { return availableCash; }
public long getReservedCash() { return reservedCash; }
}
STEP 06 / 13
코드 한 줄씩 한국어로 번역
비어 있지 않은 56줄을 모두 한국어로 옮깁니다.
비어 있지 않은 원본 줄은 하나도 생략하지 않습니다.
| 줄 | 원본 | 한국어 번역 |
|---|---|---|
| 1 | package com.example.financialcore.securities; | 실행 의미: CashWallet.java의 다음 검증 또는 설명 단계를 구성한다. |
| 3 | import jakarta.persistence.Column; | 실행 의미: CashWallet.java의 다음 검증 또는 설명 단계를 구성한다. |
| 4 | import jakarta.persistence.Entity; | 실행 의미: CashWallet.java의 다음 검증 또는 설명 단계를 구성한다. |
| 5 | import jakarta.persistence.GeneratedValue; | 실행 의미: CashWallet.java의 다음 검증 또는 설명 단계를 구성한다. |
| 6 | import jakarta.persistence.GenerationType; | 실행 의미: CashWallet.java의 다음 검증 또는 설명 단계를 구성한다. |
| 7 | import jakarta.persistence.Id; | 실행 의미: CashWallet.java의 다음 검증 또는 설명 단계를 구성한다. |
| 8 | import jakarta.persistence.Table; | 실행 의미: CashWallet.java의 다음 검증 또는 설명 단계를 구성한다. |
| 9 | import jakarta.persistence.Version; | 실행 의미: CashWallet.java의 다음 검증 또는 설명 단계를 구성한다. |
| 11 | @Entity | 실행 의미: CashWallet.java의 다음 검증 또는 설명 단계를 구성한다. |
| 12 | @Table(name = "securities_cash_wallet") | 실행 의미: CashWallet.java의 다음 검증 또는 설명 단계를 구성한다. |
| 13 | public class CashWallet { | 실행 의미: 조건·반복·함수의 실행 block을 연다. |
| 14 | @Id | 실행 의미: CashWallet.java의 다음 검증 또는 설명 단계를 구성한다. |
| 15 | @GeneratedValue(strategy = GenerationType.IDENTITY) | 실행 의미: CashWallet.java의 다음 검증 또는 설명 단계를 구성한다. |
| 16 | private Long id; | 실행 의미: CashWallet.java의 다음 검증 또는 설명 단계를 구성한다. |
| 18 | @Column(name = "investor_key", nullable = false, unique = true, length = 64) | 실행 의미: CashWallet.java의 다음 검증 또는 설명 단계를 구성한다. |
| 19 | private String investorKey; | 실행 의미: CashWallet.java의 다음 검증 또는 설명 단계를 구성한다. |
| 21 | @Column(name = "available_cash", nullable = false) | 실행 의미: CashWallet.java의 다음 검증 또는 설명 단계를 구성한다. |
| 22 | private long availableCash; | 실행 의미: CashWallet.java의 다음 검증 또는 설명 단계를 구성한다. |
| 24 | @Column(name = "reserved_cash", nullable = false) | 실행 의미: CashWallet.java의 다음 검증 또는 설명 단계를 구성한다. |
| 25 | private long reservedCash; | 실행 의미: CashWallet.java의 다음 검증 또는 설명 단계를 구성한다. |
| 27 | @Version | 실행 의미: CashWallet.java의 다음 검증 또는 설명 단계를 구성한다. |
| 28 | private long version; | 실행 의미: CashWallet.java의 다음 검증 또는 설명 단계를 구성한다. |
| 30 | protected CashWallet() {} | 실행 의미: CashWallet.java의 다음 검증 또는 설명 단계를 구성한다. |
| 32 | private CashWallet(String investorKey, long availableCash) { | 실행 의미: 조건·반복·함수의 실행 block을 연다. |
| 33 | if (investorKey == null || investorKey.isBlank()) throw new IllegalArgumentException("investorKey"); | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 34 | if (availableCash < 0) throw new IllegalArgumentException("availableCash"); | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 35 | this.investorKey = investorKey; | 실행 의미: CashWallet.java의 다음 검증 또는 설명 단계를 구성한다. |
| 36 | this.availableCash = availableCash; | 실행 의미: CashWallet.java의 다음 검증 또는 설명 단계를 구성한다. |
| 37 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 39 | public static CashWallet open(String investorKey, long availableCash) { | 실행 의미: 조건·반복·함수의 실행 block을 연다. |
| 40 | return new CashWallet(investorKey, availableCash); | 실행 의미: CashWallet.java의 다음 검증 또는 설명 단계를 구성한다. |
| 41 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 43 | public void reserve(long amount) { | 실행 의미: 조건·반복·함수의 실행 block을 연다. |
| 44 | if (amount <= 0) throw new IllegalArgumentException("amount"); | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 45 | if (availableCash < amount) throw new IllegalStateException("INSUFFICIENT_AVAILABLE_CASH"); | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 46 | availableCash -= amount; | 실행 의미: solution에서 예약액만큼 가용 현금을 실제로 차감한다. |
| 47 | reservedCash = Math.addExact(reservedCash, amount); | 실행 의미: CashWallet.java의 다음 검증 또는 설명 단계를 구성한다. |
| 48 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 50 | public void settle(long reservedAmount, long executedAmount) { | 실행 의미: 조건·반복·함수의 실행 block을 연다. |
| 51 | if (reservedAmount <= 0 || executedAmount <= 0 || executedAmount > reservedAmount) { | 실행 의미: Markdown 표 또는 PowerShell pipeline에서 값을 열이나 다음 명령으로 연결한다. |
| 52 | throw new IllegalArgumentException("settlement amount"); | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 53 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 54 | if (reservedCash < reservedAmount) throw new IllegalStateException("RESERVATION_MISMATCH"); | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 55 | reservedCash -= reservedAmount; | 실행 의미: CashWallet.java의 다음 검증 또는 설명 단계를 구성한다. |
| 56 | availableCash = Math.addExact(availableCash, reservedAmount - executedAmount); | 실행 의미: CashWallet.java의 다음 검증 또는 설명 단계를 구성한다. |
| 57 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 59 | public void releaseReservation(long amount) { | 실행 의미: 조건·반복·함수의 실행 block을 연다. |
| 60 | if (amount <= 0 || reservedCash < amount) throw new IllegalArgumentException("amount"); | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 61 | reservedCash -= amount; | 실행 의미: CashWallet.java의 다음 검증 또는 설명 단계를 구성한다. |
| 62 | availableCash = Math.addExact(availableCash, amount); | 실행 의미: CashWallet.java의 다음 검증 또는 설명 단계를 구성한다. |
| 63 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 65 | public Long getId() { return id; } | 실행 의미: CashWallet.java의 다음 검증 또는 설명 단계를 구성한다. |
| 66 | public String getInvestorKey() { return investorKey; } | 실행 의미: CashWallet.java의 다음 검증 또는 설명 단계를 구성한다. |
| 67 | public long getAvailableCash() { return availableCash; } | 실행 의미: 예약 뒤 가용 현금이 700인지 관찰한다. |
| 68 | public long getReservedCash() { return reservedCash; } | 실행 의미: 예약 뒤 예약 현금이 300인지 관찰한다. |
| 69 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
STEP 07 / 13
기존 수준의 한 줄 읽기·문법 해부
쉬운 설명 다음에 문법과 실행 순서를 정밀하게 읽습니다.
한 줄로 읽기SECURITIES solution CashWallet — availableCash 차감 복구는 reserve에서 availableCash를 amount만큼 차감해 available+reserved 총액 보존을 복구한다.
문법 해부
- .java 문법에서 선언·조건·pipeline·block 경계를 먼저 나눈다.
- manifest의 finalState와 packaged progressive test의 1_000→700/300 oracle을 서로 다른 계약으로 읽는다.
- phase state·native exit·JUnit XML hash·보존된 XML bytes·사람 판정·USER_ATTESTED external status를 서로 대체하지 않는다.
실행 순서
- 기본 트랙은 SECURITIES(증권)이며, 명시적 CARD 선택은 기본값을 덮어쓴다. 실제 실행 전 최종 선택 한 개를 selected-track.csv·근거·state에 같은 값으로 기록하고 서로 다른 reference/learner root를 확인한다.
- Prepare→VerifyStarter→RecordRed→VerifySolution→RecordGreen→Cumulative→Review 순서를 지킨다.
- test를 소유한 세 phase에서만 native exit와 exact JUnit XML 수치를 판정한다.
- 다음 cleanTest 전에 XML bytes를 고유 경로에 보존하고 runtime history hash와 다시 묶는다. Review·Q41·sealed official evidence는 각자의 별도 owner와 검증 수준으로 남긴다.
W25 조각별 정밀 해설
F12-C01 · 원문 1–12줄
- 문법 해부
- .java 문법으로 1–12줄의 선언·조건·phase·assert block을 나눈다.
- 실제 값 추적
- availableCash -= amount, reservedCash = addExact, 1_000→700/300를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- 기본 SECURITIES 또는 명시적으로 덮어쓴 CARD 중 최종 선택 한 개의 selected-track evidence와 runtime 결과에서 expected와 actual이 일치하고 owner evidence가 같은 run/hash 및 보존 XML에 연결되는 경우다. 기본/덮어쓰기 표시만 있고 실행 evidence가 없으면 NOT_RUN이다.
- 틀린 예·반례
- solution hash만으로 Green은 아니다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- phase 이름·manifest finalState·history hash·exit0 하나를 W25 증거 전체와 같다고 보지 않는다.
- 하지 않는 일
- solution hash만으로 Green은 아니다; 0/10_000은 별도 scenario가 필요하다; DB lock·동시 예약은 범위 밖이다; reference와 learner root는 서로 달라야 한다; 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다; 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
- 다음 연결
- 다음 조각 또는 F12 evidence 판정으로 상태를 넘긴다.
F12-C02 · 원문 13–24줄
- 문법 해부
- .java 문법으로 13–24줄의 선언·조건·phase·assert block을 나눈다.
- 실제 값 추적
- availableCash -= amount, reservedCash = addExact, 1_000→700/300를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- 기본 SECURITIES 또는 명시적으로 덮어쓴 CARD 중 최종 선택 한 개의 selected-track evidence와 runtime 결과에서 expected와 actual이 일치하고 owner evidence가 같은 run/hash 및 보존 XML에 연결되는 경우다. 기본/덮어쓰기 표시만 있고 실행 evidence가 없으면 NOT_RUN이다.
- 틀린 예·반례
- solution hash만으로 Green은 아니다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- phase 이름·manifest finalState·history hash·exit0 하나를 W25 증거 전체와 같다고 보지 않는다.
- 하지 않는 일
- solution hash만으로 Green은 아니다; 0/10_000은 별도 scenario가 필요하다; DB lock·동시 예약은 범위 밖이다; reference와 learner root는 서로 달라야 한다; 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다; 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
- 다음 연결
- 다음 조각 또는 F12 evidence 판정으로 상태를 넘긴다.
F12-C03 · 원문 25–36줄
- 문법 해부
- .java 문법으로 25–36줄의 선언·조건·phase·assert block을 나눈다.
- 실제 값 추적
- availableCash -= amount, reservedCash = addExact, 1_000→700/300를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- 기본 SECURITIES 또는 명시적으로 덮어쓴 CARD 중 최종 선택 한 개의 selected-track evidence와 runtime 결과에서 expected와 actual이 일치하고 owner evidence가 같은 run/hash 및 보존 XML에 연결되는 경우다. 기본/덮어쓰기 표시만 있고 실행 evidence가 없으면 NOT_RUN이다.
- 틀린 예·반례
- solution hash만으로 Green은 아니다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- phase 이름·manifest finalState·history hash·exit0 하나를 W25 증거 전체와 같다고 보지 않는다.
- 하지 않는 일
- solution hash만으로 Green은 아니다; 0/10_000은 별도 scenario가 필요하다; DB lock·동시 예약은 범위 밖이다; reference와 learner root는 서로 달라야 한다; 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다; 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
- 다음 연결
- 다음 조각 또는 F12 evidence 판정으로 상태를 넘긴다.
F12-C04 · 원문 37–48줄
- 문법 해부
- .java 문법으로 37–48줄의 선언·조건·phase·assert block을 나눈다.
- 실제 값 추적
- availableCash -= amount, reservedCash = addExact, 1_000→700/300를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- 기본 SECURITIES 또는 명시적으로 덮어쓴 CARD 중 최종 선택 한 개의 selected-track evidence와 runtime 결과에서 expected와 actual이 일치하고 owner evidence가 같은 run/hash 및 보존 XML에 연결되는 경우다. 기본/덮어쓰기 표시만 있고 실행 evidence가 없으면 NOT_RUN이다.
- 틀린 예·반례
- solution hash만으로 Green은 아니다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- phase 이름·manifest finalState·history hash·exit0 하나를 W25 증거 전체와 같다고 보지 않는다.
- 하지 않는 일
- solution hash만으로 Green은 아니다; 0/10_000은 별도 scenario가 필요하다; DB lock·동시 예약은 범위 밖이다; reference와 learner root는 서로 달라야 한다; 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다; 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
- 다음 연결
- 다음 조각 또는 F12 evidence 판정으로 상태를 넘긴다.
F12-C05 · 원문 49–60줄
- 문법 해부
- .java 문법으로 49–60줄의 선언·조건·phase·assert block을 나눈다.
- 실제 값 추적
- availableCash -= amount, reservedCash = addExact, 1_000→700/300를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- 기본 SECURITIES 또는 명시적으로 덮어쓴 CARD 중 최종 선택 한 개의 selected-track evidence와 runtime 결과에서 expected와 actual이 일치하고 owner evidence가 같은 run/hash 및 보존 XML에 연결되는 경우다. 기본/덮어쓰기 표시만 있고 실행 evidence가 없으면 NOT_RUN이다.
- 틀린 예·반례
- solution hash만으로 Green은 아니다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- phase 이름·manifest finalState·history hash·exit0 하나를 W25 증거 전체와 같다고 보지 않는다.
- 하지 않는 일
- solution hash만으로 Green은 아니다; 0/10_000은 별도 scenario가 필요하다; DB lock·동시 예약은 범위 밖이다; reference와 learner root는 서로 달라야 한다; 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다; 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
- 다음 연결
- 다음 조각 또는 F12 evidence 판정으로 상태를 넘긴다.
F12-C06 · 원문 61–69줄
- 문법 해부
- .java 문법으로 61–69줄의 선언·조건·phase·assert block을 나눈다.
- 실제 값 추적
- availableCash -= amount, reservedCash = addExact, 1_000→700/300를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- 기본 SECURITIES 또는 명시적으로 덮어쓴 CARD 중 최종 선택 한 개의 selected-track evidence와 runtime 결과에서 expected와 actual이 일치하고 owner evidence가 같은 run/hash 및 보존 XML에 연결되는 경우다. 기본/덮어쓰기 표시만 있고 실행 evidence가 없으면 NOT_RUN이다.
- 틀린 예·반례
- solution hash만으로 Green은 아니다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- phase 이름·manifest finalState·history hash·exit0 하나를 W25 증거 전체와 같다고 보지 않는다.
- 하지 않는 일
- solution hash만으로 Green은 아니다; 0/10_000은 별도 scenario가 필요하다; DB lock·동시 예약은 범위 밖이다; reference와 learner root는 서로 달라야 한다; 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다; 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
- 다음 연결
- 다음 조각 또는 F12 evidence 판정으로 상태를 넘긴다.
실행 순서 — SECURITIES solution CashWallet — availableCash 차감 복구
-
reservedCash = addExact가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 reserve에서 availableCash를 amount만큼 차감해 available+reserved 총액 보존을 복구한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘0/10_000은 별도 scenario가 필요하다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 reservedCash = addExact와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 08 / 13
실제 값 따라가기
같은 입력값이 어느 줄을 지나 어떤 결과가 되는지 추적합니다.
| 순서 | 들어온 값 | 코드가 하는 일 | 나온 값·상태 | 경계 |
|---|---|---|---|---|
| 입력 | availableCash -= amount | source 계약에 대입 | F12 실행/설명 시작 상태 | solution hash만으로 Green은 아니다 |
| 검증 | reservedCash = addExact | expected와 actual 또는 형식 대조 | 통과 또는 첫 mismatch | 0/10_000은 별도 scenario가 필요하다 |
| 증거 | LEARNER_AUTHORED after manual entry | marker·hash·row를 같은 run에 연결 | 범위가 적힌 evidence 후보 | 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다 |
실제 값 — SECURITIES solution CashWallet — availableCash 차감 복구
-
1_000→700/300가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 reserve에서 availableCash를 amount만큼 차감해 available+reserved 총액 보존을 복구한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘DB lock·동시 예약은 범위 밖이다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 1_000→700/300와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 09 / 13
Gradle·JUnit XML·PowerShell·SQL 내부에서 벌어지는 일
세 test phase, XML bytes archive, Review, 별도 Q41, USER_ATTESTED sealed 결과의 owner와 증명 범위를 구분합니다.
CashWallet.java bytes와 track·phase·hash 계약을 읽는다.
SECURITIES 기본 선택과 파일 존재·phase 이름만으로 runtime Green을 주장할 수 없다. 실제 selected-track evidence와 실행 결과는 별도다.RecordRed·RecordGreen·Cumulative에서만 native exit와 exact JUnit XML을 만든다.
solution hash만으로 Green은 아니다XML bytes를 고유 파일로 보존하고 history hash와 묶은 뒤, Review는 기존 CumulativeGreen만 인용한다. Q41은 별도 PostgreSQL evidence, sealed official status는 user-attested evidence로 남긴다.
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다첫 실패 경계 — SECURITIES solution CashWallet — availableCash 차감 복구
-
nonnegative가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 reserve에서 availableCash를 amount만큼 차감해 available+reserved 총액 보존을 복구한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘reference와 learner root는 서로 달라야 한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 nonnegative와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 10 / 13
흔한 착각과 틀린 예
그럴듯하지만 틀린 해석을 반례로 고칩니다.
❌ Prepare·VerifyStarter·VerifySolution·Review도 Gradle을 실행해 Green을 만든다.
왜 틀리나 runtime에서 test 실행을 소유하는 phase는 RecordRed·RecordGreen·Cumulative뿐이다.
바르게 읽기 각 phase history의 execution 유무와 mode를 직접 확인한다.
반례 VerifySolution은 solution hash만 검증하므로 새 JUnit XML이 없어야 정상이다.
❌ 기본 트랙이 SECURITIES이므로 CARD도 함께 실행해도 되고, 기본 배지만으로 runtime 선택·실행 증거가 완성된다.
왜 틀리나 W25 계약은 실제 사용자 근거가 있는 선택 트랙 하나와 반대 트랙 leak 부재를 요구한다.
바르게 읽기 기본 선택은 SECURITIES(증권)이며 명시적 CARD 선택은 덮어쓰기다. 실행 전 최종 선택 한 개를 selected-track.csv·근거·state에 같은 값으로 고정한다.
반례 SECURITIES 기본 배지만 보고 test 실행을 주장하거나 두 트랙 test가 함께 보이면 선택 경계를 위반한다.
❌ progressive_contract Green이면 manifest의 finalState 10_000도 증명된다.
왜 틀리나 packaged test는 1_000에서 300을 처리한 700/300만 assert한다.
바르게 읽기 10_000 finalState는 별도 learner test 또는 사람이 결박한 evidence로 증명한다.
반례 runtime은 domainContract.finalState 문자열을 parse하거나 assert하지 않는다.
❌ history에 XML SHA가 있으니 Red·Green·Cumulative XML 원본이 모두 보존됐다.
왜 틀리나 다음 cleanTest가 build/test-results의 이전 XML을 덮어쓰며 state는 bytes를 복사하지 않는다.
바르게 읽기 각 phase 직후 고유 evidence 경로로 원자 복사하고 hash를 history와 대조한다.
반례 RecordGreen 뒤에는 Red XML 경로가 사라질 수 있다.
❌ Review가 새 test를 실행해 CumulativeGreen을 다시 만들고 Q41·sealed official 결과까지 자동 확인한다.
왜 틀리나 Review는 기존 CumulativeGreen을 전제로 review entry와 leak check만 기록한다. Q41은 별도 PostgreSQL 과제이고 sealed official status는 user-attested다.
바르게 읽기 Review에서는 reviewedPhase와 history 증가만 보고, Q41 native evidence와 USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED sealed evidence를 별도로 판정한다.
반례 Review 뒤 phase는 여전히 CumulativeGreen이고 새 execution/XML·Q41 transcript·official login verification이 생기지 않는다.
STEP 11 / 13
이 코드가 보장하지 않는 것
선택 미결정·10_000 finalState·XML 보존·Review/Q41/sealed official truth처럼 이 코드가 책임지지 않는 일을 분리합니다.
solution hash만으로 Green은 아니다
이 책임을 맡는 곳: runtime Gate0/10_000은 별도 scenario가 필요하다
이 책임을 맡는 곳: external/human reviewDB lock·동시 예약은 범위 밖이다
이 책임을 맡는 곳: release manifestreference와 learner root는 서로 달라야 한다
이 책임을 맡는 곳: 운영 환경증명하지 않는 범위 — SECURITIES solution CashWallet — availableCash 차감 복구
-
LEARNER_AUTHORED after manual entry가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 reserve에서 availableCash를 amount만큼 차감해 available+reserved 총액 보존을 복구한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 LEARNER_AUTHORED after manual entry와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 12 / 13
직접 다시 써보기
뜻 → 조각 → 전체 코드 순서로 다시 씁니다.
1단계 · 뜻부터 복원
- reserve에서 availableCash를 amount만큼 차감해 available+reserved 총액 보존을 복구한다.
- 핵심 값은 availableCash -= amount, reservedCash = addExact, 1_000→700/300, nonnegative, LEARNER_AUTHORED after manual entry다.
2단계 · 코드 조각 재조립
- 1. CashWallet.java의 다음 검증 또는 설명 단계를 구성한다
- 3. CashWallet.java의 다음 검증 또는 설명 단계를 구성한다
- 4. CashWallet.java의 다음 검증 또는 설명 단계를 구성한다
- 5. CashWallet.java의 다음 검증 또는 설명 단계를 구성한다
- 6. CashWallet.java의 다음 검증 또는 설명 단계를 구성한다
- 7. CashWallet.java의 다음 검증 또는 설명 단계를 구성한다
- 8. CashWallet.java의 다음 검증 또는 설명 단계를 구성한다
- 9. CashWallet.java의 다음 검증 또는 설명 단계를 구성한다
3단계 · 파일 전체 다시 쓰기
track_learning_stages/securities/w25/solution/src/main/java/com/example/financialcore/securities/CashWallet.java을 새 파일에 다시 쓰고 expected·actual·실패·cleanup·비범위를 주석으로 표시한다.
자가 점검
- 비어 있지 않은 모든 source 줄을 한 번씩 읽었나?
- 기본 트랙을 SECURITIES(증권) 하나로 두고 기본 선택·selected-track evidence·runtime Green을 서로 분리했나?
- Review·Q41·USER_ATTESTED sealed 상태를 자동 성공으로 꾸미지 않았나?
- XML bytes archive와 첫 실패·cleanup 책임을 설명할 수 있나?
STEP 13 / 13
전체 원본 source
감사로 고정한 전체 source를 가감 없이 확인합니다.
원문 정본 전체 source 확인하기
package com.example.financialcore.securities;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import jakarta.persistence.Version;
@Entity
@Table(name = "securities_cash_wallet")
public class CashWallet {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "investor_key", nullable = false, unique = true, length = 64)
private String investorKey;
@Column(name = "available_cash", nullable = false)
private long availableCash;
@Column(name = "reserved_cash", nullable = false)
private long reservedCash;
@Version
private long version;
protected CashWallet() {}
private CashWallet(String investorKey, long availableCash) {
if (investorKey == null || investorKey.isBlank()) throw new IllegalArgumentException("investorKey");
if (availableCash < 0) throw new IllegalArgumentException("availableCash");
this.investorKey = investorKey;
this.availableCash = availableCash;
}
public static CashWallet open(String investorKey, long availableCash) {
return new CashWallet(investorKey, availableCash);
}
public void reserve(long amount) {
if (amount <= 0) throw new IllegalArgumentException("amount");
if (availableCash < amount) throw new IllegalStateException("INSUFFICIENT_AVAILABLE_CASH");
availableCash -= amount;
reservedCash = Math.addExact(reservedCash, amount);
}
public void settle(long reservedAmount, long executedAmount) {
if (reservedAmount <= 0 || executedAmount <= 0 || executedAmount > reservedAmount) {
throw new IllegalArgumentException("settlement amount");
}
if (reservedCash < reservedAmount) throw new IllegalStateException("RESERVATION_MISMATCH");
reservedCash -= reservedAmount;
availableCash = Math.addExact(availableCash, reservedAmount - executedAmount);
}
public void releaseReservation(long amount) {
if (amount <= 0 || reservedCash < amount) throw new IllegalArgumentException("amount");
reservedCash -= amount;
availableCash = Math.addExact(availableCash, amount);
}
public Long getId() { return id; }
public String getInvestorKey() { return investorKey; }
public long getAvailableCash() { return availableCash; }
public long getReservedCash() { return reservedCash; }
}
13CARD solution CardAccount — usedAmount 증가 복구
track_learning_stages/card/w25/solution/src/main/java/com/example/financialcore/card/CardAccount.java
PDF 전문 정본 · learner solution Java · 정본 · W25-F1346줄 연결46줄 번역5 chunks
CARD solution CardAccount — usedAmount 증가 복구
track_learning_stages/card/w25/solution/src/main/java/com/example/financialcore/card/CardAccount.java
PDF 전문 정본 · learner solution Java · 정본 · W25-F13STEP 01 / 13
오늘 이 코드에서 해결할 문제
무엇을 이해해야 하는지 질문부터 잡습니다.
hold에서 usedAmount를 amount만큼 더해 availableLimit+usedAmount 합계 보존을 복구한다.
- usedAmount = Math.addExact은 어느 source와 실제 결과에서 확인해야 할까?
- 첫 실패를 만드는 조건과 fail-closed 지점은 어디일까?
- 왜 ‘solution hash만으로 Green은 아니다’를 별도 경계로 남겨야 할까?
usedAmount = Math.addExactavailable=creditLimit-used1_000→300/700nonnegativeLEARNER_AUTHORED after manual entry왜 필요한가 — CARD solution CardAccount — usedAmount 증가 복구
-
usedAmount = Math.addExact가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 hold에서 usedAmount를 amount만큼 더해 availableLimit+usedAmount 합계 보존을 복구한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘solution hash만으로 Green은 아니다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 usedAmount = Math.addExact와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 02 / 13
아주 짧게: 이 코드는 왜 필요할까?
웹소설 대신 이 코드가 필요한 이유만 두 문단으로 쉽게 봅니다.
사용자의 기본 선택에 따라 이 HTML은 SECURITIES(증권)을 주 트랙으로 읽는다. CARD는 비교용이며 명시적으로 고르면 기본값을 덮어쓸 수 있다. 실제 실행은 최종 선택 한 개를 selected-track.csv·근거·state에 같은 값으로 기록하고 reference와 learner 폴더를 분리한 뒤에만 시작한다. 이 HTML 자체는 Gradle/JUnit을 실행하지 않아 NOT_RUN 상태다.
한 통장만 골라 빨강에서 초록까지 증명하는 일주일
이 파일은 hold에서 usedAmount를 amount만큼 더해 availableLimit+usedAmount 합계 보존을 복구한다. 눈으로 읽을 때는 각 줄을 검수표 한 칸처럼 보고, 입력과 다음 상태를 놓치지 않는다.
마지막 도장은 hash 확인, 세 test phase의 실제 JUnit 실행, XML bytes archive, 사람 review를 서로 구분한 뒤에만 찍는다. Review는 새 test가 아니며 Q41은 stage runtime 밖의 별도 NOT_RUN 과제, sealed official status는 USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED다. 특히 solution hash만으로 Green은 아니다
딱 여기까지만 비유와 SECURITIES 기본 배지는 실제 selected-track 근거, Gradle/JUnit 실행, XML bytes 보존, 사람 review, Q41 실행, sealed official 확인을 대신하지 않는다.
STEP 03 / 13
초등학생도 이해하는 설명
생활 비유와 실제 코드의 경계를 함께 확인합니다.
값 1: usedAmount = Math.addExact
이 파일에서 계속 확인할 고정 단서가 usedAmount = Math.addExact다.
- 코드 연결
F13 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- solution hash만으로 Green은 아니다
값 2: available=creditLimit-used
이 파일에서 계속 확인할 고정 단서가 available=creditLimit-used다.
- 코드 연결
F13 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- 0/10_000은 별도 scenario가 필요하다
값 3: 1_000→300/700
이 파일에서 계속 확인할 고정 단서가 1_000→300/700다.
- 코드 연결
F13 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- DB lock·capture/refund는 범위 밖이다
값 4: nonnegative
이 파일에서 계속 확인할 고정 단서가 nonnegative다.
- 코드 연결
F13 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- reference와 learner root는 서로 달라야 한다
값 5: LEARNER_AUTHORED after manual entry
이 파일에서 계속 확인할 고정 단서가 LEARNER_AUTHORED after manual entry다.
- 코드 연결
F13 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
STEP 04 / 13
비유 ↔ 코드 전체 연결표
감사 규칙상 연결 대상인 원본 46줄을 빠짐없이 연결합니다.
| 줄 | 정확한 원본 줄 | STARRY 비유 | 실제 뜻·입력·결과·한계 |
|---|---|---|---|
| 1줄F13-L01 | package com. |
출고표 1번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 3줄F13-L03 | import jakarta. |
출고표 3번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 4줄F13-L04 | import jakarta. |
출고표 4번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 5줄F13-L05 | import jakarta. |
출고표 5번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 6줄F13-L06 | import jakarta. |
출고표 6번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 7줄F13-L07 | import jakarta. |
출고표 7번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 8줄F13-L08 | import jakarta. |
출고표 8번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 9줄F13-L09 | import jakarta. |
출고표 9번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 11줄F13-L11 | @Entity |
출고표 11번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 12줄F13-L12 | @Table( |
출고표 12번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 13줄F13-L13 | public class CardAccount { |
출고표 13번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 조건·반복·함수의 실행 block을 연다.
|
| 14줄F13-L14 | @Id |
출고표 14번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 15줄F13-L15 | @GeneratedValue( |
출고표 15번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 16줄F13-L16 | private Long id; |
출고표 16번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 18줄F13-L18 | @Column( |
출고표 18번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 19줄F13-L19 | private String accountKey; |
출고표 19번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 21줄F13-L21 | @Column( |
출고표 21번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 22줄F13-L22 | private long creditLimit; |
출고표 22번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 24줄F13-L24 | @Column( |
출고표 24번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 25줄F13-L25 | private long usedAmount; |
출고표 25번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 27줄F13-L27 | @Version |
출고표 27번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 28줄F13-L28 | private long version; |
출고표 28번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 30줄F13-L30 | protected CardAccount( |
출고표 30번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 32줄F13-L32 | private CardAccount( |
출고표 32번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 조건·반복·함수의 실행 block을 연다.
|
| 33줄F13-L33 | if ( |
출고표 33번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 34줄F13-L34 | if ( |
출고표 34번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 35줄F13-L35 | this. |
출고표 35번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 36줄F13-L36 | this. |
출고표 36번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 37줄F13-L37 | } |
출고표 37번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 39줄F13-L39 | public static CardAccount open( |
출고표 39번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 조건·반복·함수의 실행 block을 연다.
|
| 40줄F13-L40 | return new CardAccount( |
출고표 40번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 41줄F13-L41 | } |
출고표 41번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 43줄F13-L43 | public void hold( |
출고표 43번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 조건·반복·함수의 실행 block을 연다.
|
| 44줄F13-L44 | if ( |
출고표 44번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 45줄F13-L45 | if ( |
출고표 45번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 hold 뒤 가용 한도가 700인지 관찰한다.
|
| 46줄F13-L46 | usedAmount = |
출고표 46번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 solution에서 hold 금액을 사용액에 overflow-safe하게 더한다.
|
| 47줄F13-L47 | } |
출고표 47번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 49줄F13-L49 | public void release( |
출고표 49번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 조건·반복·함수의 실행 block을 연다.
|
| 50줄F13-L50 | if ( |
출고표 50번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 51줄F13-L51 | usedAmount -= |
출고표 51번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 52줄F13-L52 | } |
출고표 52번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 54줄F13-L54 | public long availableAmount( |
출고표 54번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 hold 뒤 가용 한도가 700인지 관찰한다.
|
| 55줄F13-L55 | public Long getId( |
출고표 55번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 56줄F13-L56 | public String getAccountKey( |
출고표 56번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
|
| 57줄F13-L57 | public long getUsedAmount( |
출고표 57번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 hold 뒤 사용액이 300인지 관찰한다.
|
| 58줄F13-L58 | } |
출고표 58번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
STEP 05 / 13
원본 코드 조각
원본을 5개 의미 조각으로 나누어 그대로 확인합니다.
파일을 한꺼번에 외우지 않고 실행 의미가 이어지는 작은 조각으로 봅니다. 아래 코드는 hash로 고정한 native 정본 source에서 그대로 잘랐습니다.
package com.example.financialcore.card;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import jakarta.persistence.Version;
@Entity
@Table(name = "card_account_template")
public class CardAccount {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "account_key", nullable = false, unique = true, length = 64)
private String accountKey;
@Column(name = "credit_limit", nullable = false)
private long creditLimit;
@Column(name = "used_amount", nullable = false)
private long usedAmount;
@Version
private long version;
protected CardAccount() {}
private CardAccount(String accountKey, long creditLimit) {
if (accountKey == null || accountKey.isBlank()) throw new IllegalArgumentException("accountKey");
if (creditLimit <= 0) throw new IllegalArgumentException("creditLimit");
this.accountKey = accountKey;
this.creditLimit = creditLimit;
}
public static CardAccount open(String accountKey, long creditLimit) {
return new CardAccount(accountKey, creditLimit);
}
public void hold(long amount) {
if (amount <= 0) throw new IllegalArgumentException("amount");
if (availableAmount() < amount) throw new IllegalStateException("INSUFFICIENT_AVAILABLE_LIMIT");
usedAmount = Math.addExact(usedAmount, amount);
}
public void release(long amount) {
if (amount <= 0 || usedAmount < amount) throw new IllegalArgumentException("amount");
usedAmount -= amount;
}
public long availableAmount() { return creditLimit - usedAmount; }
public Long getId() { return id; }
public String getAccountKey() { return accountKey; }
public long getUsedAmount() { return usedAmount; }
}
STEP 06 / 13
코드 한 줄씩 한국어로 번역
비어 있지 않은 46줄을 모두 한국어로 옮깁니다.
비어 있지 않은 원본 줄은 하나도 생략하지 않습니다.
| 줄 | 원본 | 한국어 번역 |
|---|---|---|
| 1 | package com.example.financialcore.card; | 실행 의미: CardAccount.java의 다음 검증 또는 설명 단계를 구성한다. |
| 3 | import jakarta.persistence.Column; | 실행 의미: CardAccount.java의 다음 검증 또는 설명 단계를 구성한다. |
| 4 | import jakarta.persistence.Entity; | 실행 의미: CardAccount.java의 다음 검증 또는 설명 단계를 구성한다. |
| 5 | import jakarta.persistence.GeneratedValue; | 실행 의미: CardAccount.java의 다음 검증 또는 설명 단계를 구성한다. |
| 6 | import jakarta.persistence.GenerationType; | 실행 의미: CardAccount.java의 다음 검증 또는 설명 단계를 구성한다. |
| 7 | import jakarta.persistence.Id; | 실행 의미: CardAccount.java의 다음 검증 또는 설명 단계를 구성한다. |
| 8 | import jakarta.persistence.Table; | 실행 의미: CardAccount.java의 다음 검증 또는 설명 단계를 구성한다. |
| 9 | import jakarta.persistence.Version; | 실행 의미: CardAccount.java의 다음 검증 또는 설명 단계를 구성한다. |
| 11 | @Entity | 실행 의미: CardAccount.java의 다음 검증 또는 설명 단계를 구성한다. |
| 12 | @Table(name = "card_account_template") | 실행 의미: CardAccount.java의 다음 검증 또는 설명 단계를 구성한다. |
| 13 | public class CardAccount { | 실행 의미: 조건·반복·함수의 실행 block을 연다. |
| 14 | @Id | 실행 의미: CardAccount.java의 다음 검증 또는 설명 단계를 구성한다. |
| 15 | @GeneratedValue(strategy = GenerationType.IDENTITY) | 실행 의미: CardAccount.java의 다음 검증 또는 설명 단계를 구성한다. |
| 16 | private Long id; | 실행 의미: CardAccount.java의 다음 검증 또는 설명 단계를 구성한다. |
| 18 | @Column(name = "account_key", nullable = false, unique = true, length = 64) | 실행 의미: CardAccount.java의 다음 검증 또는 설명 단계를 구성한다. |
| 19 | private String accountKey; | 실행 의미: CardAccount.java의 다음 검증 또는 설명 단계를 구성한다. |
| 21 | @Column(name = "credit_limit", nullable = false) | 실행 의미: CardAccount.java의 다음 검증 또는 설명 단계를 구성한다. |
| 22 | private long creditLimit; | 실행 의미: CardAccount.java의 다음 검증 또는 설명 단계를 구성한다. |
| 24 | @Column(name = "used_amount", nullable = false) | 실행 의미: CardAccount.java의 다음 검증 또는 설명 단계를 구성한다. |
| 25 | private long usedAmount; | 실행 의미: CardAccount.java의 다음 검증 또는 설명 단계를 구성한다. |
| 27 | @Version | 실행 의미: CardAccount.java의 다음 검증 또는 설명 단계를 구성한다. |
| 28 | private long version; | 실행 의미: CardAccount.java의 다음 검증 또는 설명 단계를 구성한다. |
| 30 | protected CardAccount() {} | 실행 의미: CardAccount.java의 다음 검증 또는 설명 단계를 구성한다. |
| 32 | private CardAccount(String accountKey, long creditLimit) { | 실행 의미: 조건·반복·함수의 실행 block을 연다. |
| 33 | if (accountKey == null || accountKey.isBlank()) throw new IllegalArgumentException("accountKey"); | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 34 | if (creditLimit <= 0) throw new IllegalArgumentException("creditLimit"); | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 35 | this.accountKey = accountKey; | 실행 의미: CardAccount.java의 다음 검증 또는 설명 단계를 구성한다. |
| 36 | this.creditLimit = creditLimit; | 실행 의미: CardAccount.java의 다음 검증 또는 설명 단계를 구성한다. |
| 37 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 39 | public static CardAccount open(String accountKey, long creditLimit) { | 실행 의미: 조건·반복·함수의 실행 block을 연다. |
| 40 | return new CardAccount(accountKey, creditLimit); | 실행 의미: CardAccount.java의 다음 검증 또는 설명 단계를 구성한다. |
| 41 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 43 | public void hold(long amount) { | 실행 의미: 조건·반복·함수의 실행 block을 연다. |
| 44 | if (amount <= 0) throw new IllegalArgumentException("amount"); | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 45 | if (availableAmount() < amount) throw new IllegalStateException("INSUFFICIENT_AVAILABLE_LIMIT"); | 실행 의미: hold 뒤 가용 한도가 700인지 관찰한다. |
| 46 | usedAmount = Math.addExact(usedAmount, amount); | 실행 의미: solution에서 hold 금액을 사용액에 overflow-safe하게 더한다. |
| 47 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 49 | public void release(long amount) { | 실행 의미: 조건·반복·함수의 실행 block을 연다. |
| 50 | if (amount <= 0 || usedAmount < amount) throw new IllegalArgumentException("amount"); | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 51 | usedAmount -= amount; | 실행 의미: CardAccount.java의 다음 검증 또는 설명 단계를 구성한다. |
| 52 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 54 | public long availableAmount() { return creditLimit - usedAmount; } | 실행 의미: hold 뒤 가용 한도가 700인지 관찰한다. |
| 55 | public Long getId() { return id; } | 실행 의미: CardAccount.java의 다음 검증 또는 설명 단계를 구성한다. |
| 56 | public String getAccountKey() { return accountKey; } | 실행 의미: CardAccount.java의 다음 검증 또는 설명 단계를 구성한다. |
| 57 | public long getUsedAmount() { return usedAmount; } | 실행 의미: hold 뒤 사용액이 300인지 관찰한다. |
| 58 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
STEP 07 / 13
기존 수준의 한 줄 읽기·문법 해부
쉬운 설명 다음에 문법과 실행 순서를 정밀하게 읽습니다.
한 줄로 읽기CARD solution CardAccount — usedAmount 증가 복구는 hold에서 usedAmount를 amount만큼 더해 availableLimit+usedAmount 합계 보존을 복구한다.
문법 해부
- .java 문법에서 선언·조건·pipeline·block 경계를 먼저 나눈다.
- manifest의 finalState와 packaged progressive test의 1_000→700/300 oracle을 서로 다른 계약으로 읽는다.
- phase state·native exit·JUnit XML hash·보존된 XML bytes·사람 판정·USER_ATTESTED external status를 서로 대체하지 않는다.
실행 순서
- 기본 트랙은 SECURITIES(증권)이며, 명시적 CARD 선택은 기본값을 덮어쓴다. 실제 실행 전 최종 선택 한 개를 selected-track.csv·근거·state에 같은 값으로 기록하고 서로 다른 reference/learner root를 확인한다.
- Prepare→VerifyStarter→RecordRed→VerifySolution→RecordGreen→Cumulative→Review 순서를 지킨다.
- test를 소유한 세 phase에서만 native exit와 exact JUnit XML 수치를 판정한다.
- 다음 cleanTest 전에 XML bytes를 고유 경로에 보존하고 runtime history hash와 다시 묶는다. Review·Q41·sealed official evidence는 각자의 별도 owner와 검증 수준으로 남긴다.
W25 조각별 정밀 해설
F13-C01 · 원문 1–12줄
- 문법 해부
- .java 문법으로 1–12줄의 선언·조건·phase·assert block을 나눈다.
- 실제 값 추적
- usedAmount = Math.addExact, available=creditLimit-used, 1_000→300/700를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- 기본 SECURITIES 또는 명시적으로 덮어쓴 CARD 중 최종 선택 한 개의 selected-track evidence와 runtime 결과에서 expected와 actual이 일치하고 owner evidence가 같은 run/hash 및 보존 XML에 연결되는 경우다. 기본/덮어쓰기 표시만 있고 실행 evidence가 없으면 NOT_RUN이다.
- 틀린 예·반례
- solution hash만으로 Green은 아니다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- phase 이름·manifest finalState·history hash·exit0 하나를 W25 증거 전체와 같다고 보지 않는다.
- 하지 않는 일
- solution hash만으로 Green은 아니다; 0/10_000은 별도 scenario가 필요하다; DB lock·capture/refund는 범위 밖이다; reference와 learner root는 서로 달라야 한다; 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다; 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
- 다음 연결
- 다음 조각 또는 F13 evidence 판정으로 상태를 넘긴다.
F13-C02 · 원문 13–24줄
- 문법 해부
- .java 문법으로 13–24줄의 선언·조건·phase·assert block을 나눈다.
- 실제 값 추적
- usedAmount = Math.addExact, available=creditLimit-used, 1_000→300/700를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- 기본 SECURITIES 또는 명시적으로 덮어쓴 CARD 중 최종 선택 한 개의 selected-track evidence와 runtime 결과에서 expected와 actual이 일치하고 owner evidence가 같은 run/hash 및 보존 XML에 연결되는 경우다. 기본/덮어쓰기 표시만 있고 실행 evidence가 없으면 NOT_RUN이다.
- 틀린 예·반례
- solution hash만으로 Green은 아니다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- phase 이름·manifest finalState·history hash·exit0 하나를 W25 증거 전체와 같다고 보지 않는다.
- 하지 않는 일
- solution hash만으로 Green은 아니다; 0/10_000은 별도 scenario가 필요하다; DB lock·capture/refund는 범위 밖이다; reference와 learner root는 서로 달라야 한다; 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다; 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
- 다음 연결
- 다음 조각 또는 F13 evidence 판정으로 상태를 넘긴다.
F13-C03 · 원문 25–36줄
- 문법 해부
- .java 문법으로 25–36줄의 선언·조건·phase·assert block을 나눈다.
- 실제 값 추적
- usedAmount = Math.addExact, available=creditLimit-used, 1_000→300/700를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- 기본 SECURITIES 또는 명시적으로 덮어쓴 CARD 중 최종 선택 한 개의 selected-track evidence와 runtime 결과에서 expected와 actual이 일치하고 owner evidence가 같은 run/hash 및 보존 XML에 연결되는 경우다. 기본/덮어쓰기 표시만 있고 실행 evidence가 없으면 NOT_RUN이다.
- 틀린 예·반례
- solution hash만으로 Green은 아니다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- phase 이름·manifest finalState·history hash·exit0 하나를 W25 증거 전체와 같다고 보지 않는다.
- 하지 않는 일
- solution hash만으로 Green은 아니다; 0/10_000은 별도 scenario가 필요하다; DB lock·capture/refund는 범위 밖이다; reference와 learner root는 서로 달라야 한다; 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다; 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
- 다음 연결
- 다음 조각 또는 F13 evidence 판정으로 상태를 넘긴다.
F13-C04 · 원문 37–48줄
- 문법 해부
- .java 문법으로 37–48줄의 선언·조건·phase·assert block을 나눈다.
- 실제 값 추적
- usedAmount = Math.addExact, available=creditLimit-used, 1_000→300/700를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- 기본 SECURITIES 또는 명시적으로 덮어쓴 CARD 중 최종 선택 한 개의 selected-track evidence와 runtime 결과에서 expected와 actual이 일치하고 owner evidence가 같은 run/hash 및 보존 XML에 연결되는 경우다. 기본/덮어쓰기 표시만 있고 실행 evidence가 없으면 NOT_RUN이다.
- 틀린 예·반례
- solution hash만으로 Green은 아니다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- phase 이름·manifest finalState·history hash·exit0 하나를 W25 증거 전체와 같다고 보지 않는다.
- 하지 않는 일
- solution hash만으로 Green은 아니다; 0/10_000은 별도 scenario가 필요하다; DB lock·capture/refund는 범위 밖이다; reference와 learner root는 서로 달라야 한다; 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다; 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
- 다음 연결
- 다음 조각 또는 F13 evidence 판정으로 상태를 넘긴다.
F13-C05 · 원문 49–58줄
- 문법 해부
- .java 문법으로 49–58줄의 선언·조건·phase·assert block을 나눈다.
- 실제 값 추적
- usedAmount = Math.addExact, available=creditLimit-used, 1_000→300/700를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- 기본 SECURITIES 또는 명시적으로 덮어쓴 CARD 중 최종 선택 한 개의 selected-track evidence와 runtime 결과에서 expected와 actual이 일치하고 owner evidence가 같은 run/hash 및 보존 XML에 연결되는 경우다. 기본/덮어쓰기 표시만 있고 실행 evidence가 없으면 NOT_RUN이다.
- 틀린 예·반례
- solution hash만으로 Green은 아니다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- phase 이름·manifest finalState·history hash·exit0 하나를 W25 증거 전체와 같다고 보지 않는다.
- 하지 않는 일
- solution hash만으로 Green은 아니다; 0/10_000은 별도 scenario가 필요하다; DB lock·capture/refund는 범위 밖이다; reference와 learner root는 서로 달라야 한다; 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다; 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
- 다음 연결
- 다음 조각 또는 F13 evidence 판정으로 상태를 넘긴다.
실행 순서 — CARD solution CardAccount — usedAmount 증가 복구
-
available=creditLimit-used가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 hold에서 usedAmount를 amount만큼 더해 availableLimit+usedAmount 합계 보존을 복구한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘0/10_000은 별도 scenario가 필요하다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 available=creditLimit-used와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 08 / 13
실제 값 따라가기
같은 입력값이 어느 줄을 지나 어떤 결과가 되는지 추적합니다.
| 순서 | 들어온 값 | 코드가 하는 일 | 나온 값·상태 | 경계 |
|---|---|---|---|---|
| 입력 | usedAmount = Math.addExact | source 계약에 대입 | F13 실행/설명 시작 상태 | solution hash만으로 Green은 아니다 |
| 검증 | available=creditLimit-used | expected와 actual 또는 형식 대조 | 통과 또는 첫 mismatch | 0/10_000은 별도 scenario가 필요하다 |
| 증거 | LEARNER_AUTHORED after manual entry | marker·hash·row를 같은 run에 연결 | 범위가 적힌 evidence 후보 | 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다 |
실제 값 — CARD solution CardAccount — usedAmount 증가 복구
-
1_000→300/700가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 hold에서 usedAmount를 amount만큼 더해 availableLimit+usedAmount 합계 보존을 복구한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘DB lock·capture/refund는 범위 밖이다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 1_000→300/700와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 09 / 13
Gradle·JUnit XML·PowerShell·SQL 내부에서 벌어지는 일
세 test phase, XML bytes archive, Review, 별도 Q41, USER_ATTESTED sealed 결과의 owner와 증명 범위를 구분합니다.
CardAccount.java bytes와 track·phase·hash 계약을 읽는다.
SECURITIES 기본 선택과 파일 존재·phase 이름만으로 runtime Green을 주장할 수 없다. 실제 selected-track evidence와 실행 결과는 별도다.RecordRed·RecordGreen·Cumulative에서만 native exit와 exact JUnit XML을 만든다.
solution hash만으로 Green은 아니다XML bytes를 고유 파일로 보존하고 history hash와 묶은 뒤, Review는 기존 CumulativeGreen만 인용한다. Q41은 별도 PostgreSQL evidence, sealed official status는 user-attested evidence로 남긴다.
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다첫 실패 경계 — CARD solution CardAccount — usedAmount 증가 복구
-
nonnegative가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 hold에서 usedAmount를 amount만큼 더해 availableLimit+usedAmount 합계 보존을 복구한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘reference와 learner root는 서로 달라야 한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 nonnegative와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 10 / 13
흔한 착각과 틀린 예
그럴듯하지만 틀린 해석을 반례로 고칩니다.
❌ Prepare·VerifyStarter·VerifySolution·Review도 Gradle을 실행해 Green을 만든다.
왜 틀리나 runtime에서 test 실행을 소유하는 phase는 RecordRed·RecordGreen·Cumulative뿐이다.
바르게 읽기 각 phase history의 execution 유무와 mode를 직접 확인한다.
반례 VerifySolution은 solution hash만 검증하므로 새 JUnit XML이 없어야 정상이다.
❌ 기본 트랙이 SECURITIES이므로 CARD도 함께 실행해도 되고, 기본 배지만으로 runtime 선택·실행 증거가 완성된다.
왜 틀리나 W25 계약은 실제 사용자 근거가 있는 선택 트랙 하나와 반대 트랙 leak 부재를 요구한다.
바르게 읽기 기본 선택은 SECURITIES(증권)이며 명시적 CARD 선택은 덮어쓰기다. 실행 전 최종 선택 한 개를 selected-track.csv·근거·state에 같은 값으로 고정한다.
반례 SECURITIES 기본 배지만 보고 test 실행을 주장하거나 두 트랙 test가 함께 보이면 선택 경계를 위반한다.
❌ progressive_contract Green이면 manifest의 finalState 10_000도 증명된다.
왜 틀리나 packaged test는 1_000에서 300을 처리한 700/300만 assert한다.
바르게 읽기 10_000 finalState는 별도 learner test 또는 사람이 결박한 evidence로 증명한다.
반례 runtime은 domainContract.finalState 문자열을 parse하거나 assert하지 않는다.
❌ history에 XML SHA가 있으니 Red·Green·Cumulative XML 원본이 모두 보존됐다.
왜 틀리나 다음 cleanTest가 build/test-results의 이전 XML을 덮어쓰며 state는 bytes를 복사하지 않는다.
바르게 읽기 각 phase 직후 고유 evidence 경로로 원자 복사하고 hash를 history와 대조한다.
반례 RecordGreen 뒤에는 Red XML 경로가 사라질 수 있다.
❌ Review가 새 test를 실행해 CumulativeGreen을 다시 만들고 Q41·sealed official 결과까지 자동 확인한다.
왜 틀리나 Review는 기존 CumulativeGreen을 전제로 review entry와 leak check만 기록한다. Q41은 별도 PostgreSQL 과제이고 sealed official status는 user-attested다.
바르게 읽기 Review에서는 reviewedPhase와 history 증가만 보고, Q41 native evidence와 USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED sealed evidence를 별도로 판정한다.
반례 Review 뒤 phase는 여전히 CumulativeGreen이고 새 execution/XML·Q41 transcript·official login verification이 생기지 않는다.
STEP 11 / 13
이 코드가 보장하지 않는 것
선택 미결정·10_000 finalState·XML 보존·Review/Q41/sealed official truth처럼 이 코드가 책임지지 않는 일을 분리합니다.
solution hash만으로 Green은 아니다
이 책임을 맡는 곳: runtime Gate0/10_000은 별도 scenario가 필요하다
이 책임을 맡는 곳: external/human reviewDB lock·capture/refund는 범위 밖이다
이 책임을 맡는 곳: release manifestreference와 learner root는 서로 달라야 한다
이 책임을 맡는 곳: 운영 환경증명하지 않는 범위 — CARD solution CardAccount — usedAmount 증가 복구
-
LEARNER_AUTHORED after manual entry가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 hold에서 usedAmount를 amount만큼 더해 availableLimit+usedAmount 합계 보존을 복구한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 LEARNER_AUTHORED after manual entry와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 12 / 13
직접 다시 써보기
뜻 → 조각 → 전체 코드 순서로 다시 씁니다.
1단계 · 뜻부터 복원
- hold에서 usedAmount를 amount만큼 더해 availableLimit+usedAmount 합계 보존을 복구한다.
- 핵심 값은 usedAmount = Math.addExact, available=creditLimit-used, 1_000→300/700, nonnegative, LEARNER_AUTHORED after manual entry다.
2단계 · 코드 조각 재조립
- 1. CardAccount.java의 다음 검증 또는 설명 단계를 구성한다
- 3. CardAccount.java의 다음 검증 또는 설명 단계를 구성한다
- 4. CardAccount.java의 다음 검증 또는 설명 단계를 구성한다
- 5. CardAccount.java의 다음 검증 또는 설명 단계를 구성한다
- 6. CardAccount.java의 다음 검증 또는 설명 단계를 구성한다
- 7. CardAccount.java의 다음 검증 또는 설명 단계를 구성한다
- 8. CardAccount.java의 다음 검증 또는 설명 단계를 구성한다
- 9. CardAccount.java의 다음 검증 또는 설명 단계를 구성한다
3단계 · 파일 전체 다시 쓰기
track_learning_stages/card/w25/solution/src/main/java/com/example/financialcore/card/CardAccount.java을 새 파일에 다시 쓰고 expected·actual·실패·cleanup·비범위를 주석으로 표시한다.
자가 점검
- 비어 있지 않은 모든 source 줄을 한 번씩 읽었나?
- 기본 트랙을 SECURITIES(증권) 하나로 두고 기본 선택·selected-track evidence·runtime Green을 서로 분리했나?
- Review·Q41·USER_ATTESTED sealed 상태를 자동 성공으로 꾸미지 않았나?
- XML bytes archive와 첫 실패·cleanup 책임을 설명할 수 있나?
STEP 13 / 13
전체 원본 source
감사로 고정한 전체 source를 가감 없이 확인합니다.
원문 정본 전체 source 확인하기
package com.example.financialcore.card;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import jakarta.persistence.Version;
@Entity
@Table(name = "card_account_template")
public class CardAccount {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "account_key", nullable = false, unique = true, length = 64)
private String accountKey;
@Column(name = "credit_limit", nullable = false)
private long creditLimit;
@Column(name = "used_amount", nullable = false)
private long usedAmount;
@Version
private long version;
protected CardAccount() {}
private CardAccount(String accountKey, long creditLimit) {
if (accountKey == null || accountKey.isBlank()) throw new IllegalArgumentException("accountKey");
if (creditLimit <= 0) throw new IllegalArgumentException("creditLimit");
this.accountKey = accountKey;
this.creditLimit = creditLimit;
}
public static CardAccount open(String accountKey, long creditLimit) {
return new CardAccount(accountKey, creditLimit);
}
public void hold(long amount) {
if (amount <= 0) throw new IllegalArgumentException("amount");
if (availableAmount() < amount) throw new IllegalStateException("INSUFFICIENT_AVAILABLE_LIMIT");
usedAmount = Math.addExact(usedAmount, amount);
}
public void release(long amount) {
if (amount <= 0 || usedAmount < amount) throw new IllegalArgumentException("amount");
usedAmount -= amount;
}
public long availableAmount() { return creditLimit - usedAmount; }
public Long getId() { return id; }
public String getAccountKey() { return accountKey; }
public long getUsedAmount() { return usedAmount; }
}
14D4 VerifySolution — solution hash와 별도 10_000 oracle 경계
illustrative/powershell/W25-D4-verify-solution.ps1
학습용 예시 · W25 phase wrapper · 정본 답안 아님 · 로컬 미실행 · 학습용 예시 · 정본 답안 아님 · NOT_RUN · W25-F1425줄 연결25줄 번역3 chunks
D4 VerifySolution — solution hash와 별도 10_000 oracle 경계
illustrative/powershell/W25-D4-verify-solution.ps1
학습용 예시 · W25 phase wrapper · 정본 답안 아님 · 로컬 미실행 · 학습용 예시 · 정본 답안 아님 · NOT_RUN · W25-F14STEP 01 / 13
오늘 이 코드에서 해결할 문제
무엇을 이해해야 하는지 질문부터 잡습니다.
LearnerRed 이후 선택 트랙 solution canonical/raw hash를 확인하되 새 Gradle/XML Green이 없음을 확인한다.
- LearnerRed은 어느 source와 실제 결과에서 확인해야 할까?
- 첫 실패를 만드는 조건과 fail-closed 지점은 어디일까?
- 왜 ‘hash 일치는 실행 성공이 아니다’를 별도 경계로 남겨야 할까?
LearnerRedSolutionVerifiedsolutionSha2560/10_000 needs separate testruntime_claim=false왜 필요한가 — D4 VerifySolution — solution hash와 별도 10_000 oracle 경계
-
LearnerRed가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 LearnerRed 이후 선택 트랙 solution canonical/raw hash를 확인하되 새 Gradle/XML Green이 없음을 확인한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘hash 일치는 실행 성공이 아니다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 LearnerRed와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 02 / 13
아주 짧게: 이 코드는 왜 필요할까?
웹소설 대신 이 코드가 필요한 이유만 두 문단으로 쉽게 봅니다.
사용자의 기본 선택에 따라 이 HTML은 SECURITIES(증권)을 주 트랙으로 읽는다. CARD는 비교용이며 명시적으로 고르면 기본값을 덮어쓸 수 있다. 실제 실행은 최종 선택 한 개를 selected-track.csv·근거·state에 같은 값으로 기록하고 reference와 learner 폴더를 분리한 뒤에만 시작한다. 이 HTML 자체는 Gradle/JUnit을 실행하지 않아 NOT_RUN 상태다.
한 통장만 골라 빨강에서 초록까지 증명하는 일주일
이 파일은 LearnerRed 이후 선택 트랙 solution canonical/raw hash를 확인하되 새 Gradle/XML Green이 없음을 확인한다. 눈으로 읽을 때는 각 줄을 검수표 한 칸처럼 보고, 입력과 다음 상태를 놓치지 않는다.
마지막 도장은 hash 확인, 세 test phase의 실제 JUnit 실행, XML bytes archive, 사람 review를 서로 구분한 뒤에만 찍는다. Review는 새 test가 아니며 Q41은 stage runtime 밖의 별도 NOT_RUN 과제, sealed official status는 USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED다. 특히 hash 일치는 실행 성공이 아니다
딱 여기까지만 비유와 SECURITIES 기본 배지는 실제 selected-track 근거, Gradle/JUnit 실행, XML bytes 보존, 사람 review, Q41 실행, sealed official 확인을 대신하지 않는다.
STEP 03 / 13
초등학생도 이해하는 설명
생활 비유와 실제 코드의 경계를 함께 확인합니다.
값 1: LearnerRed
이 파일에서 계속 확인할 고정 단서가 LearnerRed다.
- 코드 연결
F14 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- hash 일치는 실행 성공이 아니다
값 2: SolutionVerified
이 파일에서 계속 확인할 고정 단서가 SolutionVerified다.
- 코드 연결
F14 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- manifest finalState는 runtime이 parse/assert하지 않는다
값 3: solutionSha256
이 파일에서 계속 확인할 고정 단서가 solutionSha256다.
- 코드 연결
F14 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- reference와 learner root는 서로 달라야 한다
값 4: 0/10_000 needs separate test
이 파일에서 계속 확인할 고정 단서가 0/10_000 needs separate test다.
- 코드 연결
F14 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
값 5: runtime_claim=false
이 파일에서 계속 확인할 고정 단서가 runtime_claim=false다.
- 코드 연결
F14 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
STEP 04 / 13
비유 ↔ 코드 전체 연결표
감사 규칙상 연결 대상인 원본 25줄을 빠짐없이 연결합니다.
| 줄 | 정확한 원본 줄 | STARRY 비유 | 실제 뜻·입력·결과·한계 |
|---|---|---|---|
| 1줄F14-L01 | # W25 PDF p23-p31의 VerifySolution 흐름을 정리한 학습용 예시다. |
출고표 1번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 solution canonical/raw hash만 검증하고 새 Green을 만들지 않는 phase다.
|
| 2줄F14-L02 | # solution canonical/ |
출고표 2번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다.
|
| 3줄F14-L03 | $ErrorActionPreference = |
출고표 3번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 PowerShell 오류를 계속 진행하지 않고 중단시키는 기본 정책을 둔다.
|
| 4줄F14-L04 | $ReferenceRoot = |
출고표 4번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 입력 경로를 실제 절대 경로로 확인한다.
|
| 5줄F14-L05 | $LearnerRoot = |
출고표 5번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 입력 경로를 실제 절대 경로로 확인한다.
|
| 6줄F14-L06 | if ( |
출고표 6번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 조건·반복·함수의 실행 block을 연다.
|
| 7줄F14-L07 | throw 'reference and learner roots must be different' |
출고표 7번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 8줄F14-L08 | } |
출고표 8번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 9줄F14-L09 | $Before = |
출고표 9번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 JSON text를 필드로 접근 가능한 PowerShell object로 바꾼다.
|
| 10줄F14-L10 | if ( |
출고표 10번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 solution canonical/raw hash만 검증하고 새 Green을 만들지 않는 phase다.
|
| 12줄F14-L12 | $Runner = |
출고표 12번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 13줄F14-L13 | & powershell. |
출고표 13번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W25-D4-verify-solution.ps1의 다음 검증 또는 설명 단계를 구성한다.
|
| 14줄F14-L14 | -ReferenceRoot $ReferenceRoot -LearnerRoot $LearnerRoot -Week 25 -Phase VerifySolution -TimeoutSeconds 1200 |
출고표 14번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 solution canonical/raw hash만 검증하고 새 Green을 만들지 않는 phase다.
|
| 15줄F14-L15 | if ( |
출고표 15번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 solution canonical/raw hash만 검증하고 새 Green을 만들지 않는 phase다.
|
| 17줄F14-L17 | $StatePath = |
출고표 17번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 18줄F14-L18 | $State = |
출고표 18번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 JSON text를 필드로 접근 가능한 PowerShell object로 바꾼다.
|
| 19줄F14-L19 | $Entry = |
출고표 19번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 20줄F14-L20 | if ( |
출고표 20번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 solution canonical/raw hash만 검증하고 새 Green을 만들지 않는 phase다.
|
| 21줄F14-L21 | throw 'W25 VerifySolution state mismatch' |
출고표 21번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 solution canonical/raw hash만 검증하고 새 Green을 만들지 않는 phase다.
|
| 22줄F14-L22 | } |
출고표 22번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 23줄F14-L23 | if ( |
출고표 23번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 학습자가 직접 소유하는 main Java 경로와 starter/solution hash를 묶는다.
|
| 24줄F14-L24 | throw 'VerifySolution must record authoredTarget without new execution evidence' |
출고표 24번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 학습자가 직접 소유하는 main Java 경로와 starter/solution hash를 묶는다.
|
| 25줄F14-L25 | } |
출고표 25번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 26줄F14-L26 | $Hash = |
출고표 26번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 현재 bytes를 64자리 digest로 evidence에 결박한다.
|
| 27줄F14-L27 | "W25_SOLUTION_HASH_VERIFIED phase= |
출고표 27번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 현재 bytes를 64자리 digest로 evidence에 결박한다.
|
STEP 05 / 13
원본 코드 조각
원본을 3개 의미 조각으로 나누어 그대로 확인합니다.
파일을 한꺼번에 외우지 않고 실행 의미가 이어지는 작은 조각으로 봅니다. 아래 코드는 prompt·fixture·가정을 밝힌 학습용 예시 source이며, 제공 정본 답안이나 실행 결과가 아닌 NOT_RUN 자료입니다.
# W25 PDF p23-p31의 VerifySolution 흐름을 정리한 학습용 예시다.
# solution canonical/raw hash와 learner ownership을 검증하지만 새 test Green은 만들지 않는다.
$ErrorActionPreference = 'Stop'
$ReferenceRoot = (Resolve-Path -LiteralPath $env:FINANCIAL_IT_REFERENCE_ROOT).Path
$LearnerRoot = (Resolve-Path -LiteralPath $env:FINANCIAL_IT_LEARNER_ROOT).Path
if ([string]::Equals($ReferenceRoot, $LearnerRoot, [StringComparison]::OrdinalIgnoreCase)) {
throw 'reference and learner roots must be different'
}
$Before = Get-Content -Raw -LiteralPath (Join-Path $LearnerRoot '.track-learning-stage.json') | ConvertFrom-Json
if ($Before.phase -cne 'LearnerRed') { throw 'VerifySolution requires LearnerRed' }
$Runner = Join-Path $ReferenceRoot 'scripts\apply-track-learning-stage.ps1'
& powershell.exe -NoProfile -ExecutionPolicy Bypass -File $Runner `
-ReferenceRoot $ReferenceRoot -LearnerRoot $LearnerRoot -Week 25 -Phase VerifySolution -TimeoutSeconds 1200
if ($LASTEXITCODE -ne 0) { throw "W25 VerifySolution native exit=$LASTEXITCODE" }
$StatePath = Join-Path $LearnerRoot '.track-learning-stage.json'
$State = Get-Content -Raw -LiteralPath $StatePath | ConvertFrom-Json
$Entry = @($State.history)[-1]
if ($State.phase -cne 'SolutionVerified' -or $Entry.phase -cne 'VerifySolution') {
throw 'W25 VerifySolution state mismatch'
}
if ($null -eq $Entry.authoredTarget -or $null -ne $Entry.execution) {
throw 'VerifySolution must record authoredTarget without new execution evidence'
}
$Hash = (Get-FileHash -LiteralPath $StatePath -Algorithm SHA256).Hash.ToLowerInvariant()
"W25_SOLUTION_HASH_VERIFIED phase=SolutionVerified runtime_claim=false state_sha256=$Hash"
STEP 06 / 13
코드 한 줄씩 한국어로 번역
비어 있지 않은 25줄을 모두 한국어로 옮깁니다.
비어 있지 않은 원본 줄은 하나도 생략하지 않습니다.
| 줄 | 원본 | 한국어 번역 |
|---|---|---|
| 1 | # W25 PDF p23-p31의 VerifySolution 흐름을 정리한 학습용 예시다. | 문서 의미: solution canonical/raw hash만 검증하고 새 Green을 만들지 않는 phase다. |
| 2 | # solution canonical/raw hash와 learner ownership을 검증하지만 새 test Green은 만들지 않는다. | 문서 의미: 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다. |
| 3 | $ErrorActionPreference = 'Stop' | 실행 의미: PowerShell 오류를 계속 진행하지 않고 중단시키는 기본 정책을 둔다. |
| 4 | $ReferenceRoot = (Resolve-Path -LiteralPath $env:FINANCIAL_IT_REFERENCE_ROOT).Path | 실행 의미: 입력 경로를 실제 절대 경로로 확인한다. |
| 5 | $LearnerRoot = (Resolve-Path -LiteralPath $env:FINANCIAL_IT_LEARNER_ROOT).Path | 실행 의미: 입력 경로를 실제 절대 경로로 확인한다. |
| 6 | if ([string]::Equals($ReferenceRoot, $LearnerRoot, [StringComparison]::OrdinalIgnoreCase)) { | 실행 의미: 조건·반복·함수의 실행 block을 연다. |
| 7 | throw 'reference and learner roots must be different' | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 8 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 9 | $Before = Get-Content -Raw -LiteralPath (Join-Path $LearnerRoot '.track-learning-stage.json') | ConvertFrom-Json | 실행 의미: JSON text를 필드로 접근 가능한 PowerShell object로 바꾼다. |
| 10 | if ($Before.phase -cne 'LearnerRed') { throw 'VerifySolution requires LearnerRed' } | 실행 의미: solution canonical/raw hash만 검증하고 새 Green을 만들지 않는 phase다. |
| 12 | $Runner = Join-Path $ReferenceRoot 'scripts\apply-track-learning-stage.ps1' | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 13 | & powershell.exe -NoProfile -ExecutionPolicy Bypass -File $Runner ` | 실행 의미: W25-D4-verify-solution.ps1의 다음 검증 또는 설명 단계를 구성한다. |
| 14 | -ReferenceRoot $ReferenceRoot -LearnerRoot $LearnerRoot -Week 25 -Phase VerifySolution -TimeoutSeconds 1200 | 실행 의미: solution canonical/raw hash만 검증하고 새 Green을 만들지 않는 phase다. |
| 15 | if ($LASTEXITCODE -ne 0) { throw "W25 VerifySolution native exit=$LASTEXITCODE" } | 실행 의미: solution canonical/raw hash만 검증하고 새 Green을 만들지 않는 phase다. |
| 17 | $StatePath = Join-Path $LearnerRoot '.track-learning-stage.json' | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 18 | $State = Get-Content -Raw -LiteralPath $StatePath | ConvertFrom-Json | 실행 의미: JSON text를 필드로 접근 가능한 PowerShell object로 바꾼다. |
| 19 | $Entry = @($State.history)[-1] | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 20 | if ($State.phase -cne 'SolutionVerified' -or $Entry.phase -cne 'VerifySolution') { | 실행 의미: solution canonical/raw hash만 검증하고 새 Green을 만들지 않는 phase다. |
| 21 | throw 'W25 VerifySolution state mismatch' | 실행 의미: solution canonical/raw hash만 검증하고 새 Green을 만들지 않는 phase다. |
| 22 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 23 | if ($null -eq $Entry.authoredTarget -or $null -ne $Entry.execution) { | 실행 의미: 학습자가 직접 소유하는 main Java 경로와 starter/solution hash를 묶는다. |
| 24 | throw 'VerifySolution must record authoredTarget without new execution evidence' | 실행 의미: 학습자가 직접 소유하는 main Java 경로와 starter/solution hash를 묶는다. |
| 25 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 26 | $Hash = (Get-FileHash -LiteralPath $StatePath -Algorithm SHA256).Hash.ToLowerInvariant() | 실행 의미: 현재 bytes를 64자리 digest로 evidence에 결박한다. |
| 27 | "W25_SOLUTION_HASH_VERIFIED phase=SolutionVerified runtime_claim=false state_sha256=$Hash" | 실행 의미: 현재 bytes를 64자리 digest로 evidence에 결박한다. |
STEP 07 / 13
기존 수준의 한 줄 읽기·문법 해부
쉬운 설명 다음에 문법과 실행 순서를 정밀하게 읽습니다.
한 줄로 읽기D4 VerifySolution — solution hash와 별도 10_000 oracle 경계는 LearnerRed 이후 선택 트랙 solution canonical/raw hash를 확인하되 새 Gradle/XML Green이 없음을 확인한다.
문법 해부
- .ps1 문법에서 선언·조건·pipeline·block 경계를 먼저 나눈다.
- manifest의 finalState와 packaged progressive test의 1_000→700/300 oracle을 서로 다른 계약으로 읽는다.
- phase state·native exit·JUnit XML hash·보존된 XML bytes·사람 판정·USER_ATTESTED external status를 서로 대체하지 않는다.
실행 순서
- 기본 트랙은 SECURITIES(증권)이며, 명시적 CARD 선택은 기본값을 덮어쓴다. 실제 실행 전 최종 선택 한 개를 selected-track.csv·근거·state에 같은 값으로 기록하고 서로 다른 reference/learner root를 확인한다.
- Prepare→VerifyStarter→RecordRed→VerifySolution→RecordGreen→Cumulative→Review 순서를 지킨다.
- test를 소유한 세 phase에서만 native exit와 exact JUnit XML 수치를 판정한다.
- 다음 cleanTest 전에 XML bytes를 고유 경로에 보존하고 runtime history hash와 다시 묶는다. Review·Q41·sealed official evidence는 각자의 별도 owner와 검증 수준으로 남긴다.
W25 조각별 정밀 해설
F14-C01 · 원문 1–12줄
- 문법 해부
- .ps1 문법으로 1–12줄의 선언·조건·phase·assert block을 나눈다.
- 실제 값 추적
- LearnerRed, SolutionVerified, solutionSha256를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- 기본 SECURITIES 또는 명시적으로 덮어쓴 CARD 중 최종 선택 한 개의 selected-track evidence와 runtime 결과에서 expected와 actual이 일치하고 owner evidence가 같은 run/hash 및 보존 XML에 연결되는 경우다. 기본/덮어쓰기 표시만 있고 실행 evidence가 없으면 NOT_RUN이다.
- 틀린 예·반례
- hash 일치는 실행 성공이 아니다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- phase 이름·manifest finalState·history hash·exit0 하나를 W25 증거 전체와 같다고 보지 않는다.
- 하지 않는 일
- hash 일치는 실행 성공이 아니다; manifest finalState는 runtime이 parse/assert하지 않는다; reference와 learner root는 서로 달라야 한다; 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다; 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
- 다음 연결
- 다음 조각 또는 F14 evidence 판정으로 상태를 넘긴다.
F14-C02 · 원문 13–24줄
- 문법 해부
- .ps1 문법으로 13–24줄의 선언·조건·phase·assert block을 나눈다.
- 실제 값 추적
- LearnerRed, SolutionVerified, solutionSha256를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- 기본 SECURITIES 또는 명시적으로 덮어쓴 CARD 중 최종 선택 한 개의 selected-track evidence와 runtime 결과에서 expected와 actual이 일치하고 owner evidence가 같은 run/hash 및 보존 XML에 연결되는 경우다. 기본/덮어쓰기 표시만 있고 실행 evidence가 없으면 NOT_RUN이다.
- 틀린 예·반례
- hash 일치는 실행 성공이 아니다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- phase 이름·manifest finalState·history hash·exit0 하나를 W25 증거 전체와 같다고 보지 않는다.
- 하지 않는 일
- hash 일치는 실행 성공이 아니다; manifest finalState는 runtime이 parse/assert하지 않는다; reference와 learner root는 서로 달라야 한다; 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다; 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
- 다음 연결
- 다음 조각 또는 F14 evidence 판정으로 상태를 넘긴다.
F14-C03 · 원문 25–27줄
- 문법 해부
- .ps1 문법으로 25–27줄의 선언·조건·phase·assert block을 나눈다.
- 실제 값 추적
- LearnerRed, SolutionVerified, solutionSha256를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- 기본 SECURITIES 또는 명시적으로 덮어쓴 CARD 중 최종 선택 한 개의 selected-track evidence와 runtime 결과에서 expected와 actual이 일치하고 owner evidence가 같은 run/hash 및 보존 XML에 연결되는 경우다. 기본/덮어쓰기 표시만 있고 실행 evidence가 없으면 NOT_RUN이다.
- 틀린 예·반례
- hash 일치는 실행 성공이 아니다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- phase 이름·manifest finalState·history hash·exit0 하나를 W25 증거 전체와 같다고 보지 않는다.
- 하지 않는 일
- hash 일치는 실행 성공이 아니다; manifest finalState는 runtime이 parse/assert하지 않는다; reference와 learner root는 서로 달라야 한다; 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다; 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
- 다음 연결
- 다음 조각 또는 F14 evidence 판정으로 상태를 넘긴다.
실행 순서 — D4 VerifySolution — solution hash와 별도 10_000 oracle 경계
-
SolutionVerified가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 LearnerRed 이후 선택 트랙 solution canonical/raw hash를 확인하되 새 Gradle/XML Green이 없음을 확인한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘manifest finalState는 runtime이 parse/assert하지 않는다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 SolutionVerified와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 08 / 13
실제 값 따라가기
같은 입력값이 어느 줄을 지나 어떤 결과가 되는지 추적합니다.
| 순서 | 들어온 값 | 코드가 하는 일 | 나온 값·상태 | 경계 |
|---|---|---|---|---|
| 입력 | LearnerRed | source 계약에 대입 | F14 실행/설명 시작 상태 | hash 일치는 실행 성공이 아니다 |
| 검증 | SolutionVerified | expected와 actual 또는 형식 대조 | 통과 또는 첫 mismatch | manifest finalState는 runtime이 parse/assert하지 않는다 |
| 증거 | runtime_claim=false | marker·hash·row를 같은 run에 연결 | 범위가 적힌 evidence 후보 | 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다 |
실제 값 — D4 VerifySolution — solution hash와 별도 10_000 oracle 경계
-
solutionSha256가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 LearnerRed 이후 선택 트랙 solution canonical/raw hash를 확인하되 새 Gradle/XML Green이 없음을 확인한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘reference와 learner root는 서로 달라야 한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 solutionSha256와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 09 / 13
Gradle·JUnit XML·PowerShell·SQL 내부에서 벌어지는 일
세 test phase, XML bytes archive, Review, 별도 Q41, USER_ATTESTED sealed 결과의 owner와 증명 범위를 구분합니다.
W25-D4-verify-solution.ps1 bytes와 track·phase·hash 계약을 읽는다.
SECURITIES 기본 선택과 파일 존재·phase 이름만으로 runtime Green을 주장할 수 없다. 실제 selected-track evidence와 실행 결과는 별도다.RecordRed·RecordGreen·Cumulative에서만 native exit와 exact JUnit XML을 만든다.
hash 일치는 실행 성공이 아니다XML bytes를 고유 파일로 보존하고 history hash와 묶은 뒤, Review는 기존 CumulativeGreen만 인용한다. Q41은 별도 PostgreSQL evidence, sealed official status는 user-attested evidence로 남긴다.
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다첫 실패 경계 — D4 VerifySolution — solution hash와 별도 10_000 oracle 경계
-
0/10_000 needs separate test가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 LearnerRed 이후 선택 트랙 solution canonical/raw hash를 확인하되 새 Gradle/XML Green이 없음을 확인한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 0/10_000 needs separate test와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 10 / 13
흔한 착각과 틀린 예
그럴듯하지만 틀린 해석을 반례로 고칩니다.
❌ Prepare·VerifyStarter·VerifySolution·Review도 Gradle을 실행해 Green을 만든다.
왜 틀리나 runtime에서 test 실행을 소유하는 phase는 RecordRed·RecordGreen·Cumulative뿐이다.
바르게 읽기 각 phase history의 execution 유무와 mode를 직접 확인한다.
반례 VerifySolution은 solution hash만 검증하므로 새 JUnit XML이 없어야 정상이다.
❌ 기본 트랙이 SECURITIES이므로 CARD도 함께 실행해도 되고, 기본 배지만으로 runtime 선택·실행 증거가 완성된다.
왜 틀리나 W25 계약은 실제 사용자 근거가 있는 선택 트랙 하나와 반대 트랙 leak 부재를 요구한다.
바르게 읽기 기본 선택은 SECURITIES(증권)이며 명시적 CARD 선택은 덮어쓰기다. 실행 전 최종 선택 한 개를 selected-track.csv·근거·state에 같은 값으로 고정한다.
반례 SECURITIES 기본 배지만 보고 test 실행을 주장하거나 두 트랙 test가 함께 보이면 선택 경계를 위반한다.
❌ progressive_contract Green이면 manifest의 finalState 10_000도 증명된다.
왜 틀리나 packaged test는 1_000에서 300을 처리한 700/300만 assert한다.
바르게 읽기 10_000 finalState는 별도 learner test 또는 사람이 결박한 evidence로 증명한다.
반례 runtime은 domainContract.finalState 문자열을 parse하거나 assert하지 않는다.
❌ history에 XML SHA가 있으니 Red·Green·Cumulative XML 원본이 모두 보존됐다.
왜 틀리나 다음 cleanTest가 build/test-results의 이전 XML을 덮어쓰며 state는 bytes를 복사하지 않는다.
바르게 읽기 각 phase 직후 고유 evidence 경로로 원자 복사하고 hash를 history와 대조한다.
반례 RecordGreen 뒤에는 Red XML 경로가 사라질 수 있다.
❌ Review가 새 test를 실행해 CumulativeGreen을 다시 만들고 Q41·sealed official 결과까지 자동 확인한다.
왜 틀리나 Review는 기존 CumulativeGreen을 전제로 review entry와 leak check만 기록한다. Q41은 별도 PostgreSQL 과제이고 sealed official status는 user-attested다.
바르게 읽기 Review에서는 reviewedPhase와 history 증가만 보고, Q41 native evidence와 USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED sealed evidence를 별도로 판정한다.
반례 Review 뒤 phase는 여전히 CumulativeGreen이고 새 execution/XML·Q41 transcript·official login verification이 생기지 않는다.
STEP 11 / 13
이 코드가 보장하지 않는 것
선택 미결정·10_000 finalState·XML 보존·Review/Q41/sealed official truth처럼 이 코드가 책임지지 않는 일을 분리합니다.
hash 일치는 실행 성공이 아니다
이 책임을 맡는 곳: runtime Gatemanifest finalState는 runtime이 parse/assert하지 않는다
이 책임을 맡는 곳: external/human reviewreference와 learner root는 서로 달라야 한다
이 책임을 맡는 곳: release manifest기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
이 책임을 맡는 곳: 운영 환경증명하지 않는 범위 — D4 VerifySolution — solution hash와 별도 10_000 oracle 경계
-
runtime_claim=false가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 LearnerRed 이후 선택 트랙 solution canonical/raw hash를 확인하되 새 Gradle/XML Green이 없음을 확인한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 runtime_claim=false와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 12 / 13
직접 다시 써보기
뜻 → 조각 → 전체 코드 순서로 다시 씁니다.
1단계 · 뜻부터 복원
- LearnerRed 이후 선택 트랙 solution canonical/raw hash를 확인하되 새 Gradle/XML Green이 없음을 확인한다.
- 핵심 값은 LearnerRed, SolutionVerified, solutionSha256, 0/10_000 needs separate test, runtime_claim=false다.
2단계 · 코드 조각 재조립
- 1. solution canonical/raw hash만 검증하고 새 Green을 만들지 않는 phase다
- 2. 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다
- 3. PowerShell 오류를 계속 진행하지 않고 중단시키는 기본 정책을 둔다
- 4. 입력 경로를 실제 절대 경로로 확인한다
- 5. 입력 경로를 실제 절대 경로로 확인한다
- 6. 조건·반복·함수의 실행 block을 연다
- 7. 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다
- 8. 앞에서 연 block 또는 호출 범위를 닫는다
3단계 · 파일 전체 다시 쓰기
illustrative/powershell/W25-D4-verify-solution.ps1을 새 파일에 다시 쓰고 expected·actual·실패·cleanup·비범위를 주석으로 표시한다.
자가 점검
- 비어 있지 않은 모든 source 줄을 한 번씩 읽었나?
- 기본 트랙을 SECURITIES(증권) 하나로 두고 기본 선택·selected-track evidence·runtime Green을 서로 분리했나?
- Review·Q41·USER_ATTESTED sealed 상태를 자동 성공으로 꾸미지 않았나?
- XML bytes archive와 첫 실패·cleanup 책임을 설명할 수 있나?
STEP 13 / 13
전체 원본 source
감사로 고정한 전체 source를 가감 없이 확인합니다.
학습용 예시 전체 확인하기 · 정본 답안 아님 · NOT_RUN
# W25 PDF p23-p31의 VerifySolution 흐름을 정리한 학습용 예시다.
# solution canonical/raw hash와 learner ownership을 검증하지만 새 test Green은 만들지 않는다.
$ErrorActionPreference = 'Stop'
$ReferenceRoot = (Resolve-Path -LiteralPath $env:FINANCIAL_IT_REFERENCE_ROOT).Path
$LearnerRoot = (Resolve-Path -LiteralPath $env:FINANCIAL_IT_LEARNER_ROOT).Path
if ([string]::Equals($ReferenceRoot, $LearnerRoot, [StringComparison]::OrdinalIgnoreCase)) {
throw 'reference and learner roots must be different'
}
$Before = Get-Content -Raw -LiteralPath (Join-Path $LearnerRoot '.track-learning-stage.json') | ConvertFrom-Json
if ($Before.phase -cne 'LearnerRed') { throw 'VerifySolution requires LearnerRed' }
$Runner = Join-Path $ReferenceRoot 'scripts\apply-track-learning-stage.ps1'
& powershell.exe -NoProfile -ExecutionPolicy Bypass -File $Runner `
-ReferenceRoot $ReferenceRoot -LearnerRoot $LearnerRoot -Week 25 -Phase VerifySolution -TimeoutSeconds 1200
if ($LASTEXITCODE -ne 0) { throw "W25 VerifySolution native exit=$LASTEXITCODE" }
$StatePath = Join-Path $LearnerRoot '.track-learning-stage.json'
$State = Get-Content -Raw -LiteralPath $StatePath | ConvertFrom-Json
$Entry = @($State.history)[-1]
if ($State.phase -cne 'SolutionVerified' -or $Entry.phase -cne 'VerifySolution') {
throw 'W25 VerifySolution state mismatch'
}
if ($null -eq $Entry.authoredTarget -or $null -ne $Entry.execution) {
throw 'VerifySolution must record authoredTarget without new execution evidence'
}
$Hash = (Get-FileHash -LiteralPath $StatePath -Algorithm SHA256).Hash.ToLowerInvariant()
"W25_SOLUTION_HASH_VERIFIED phase=SolutionVerified runtime_claim=false state_sha256=$Hash"
15D5 RecordGreen — current selector exact Green과 XML archive
illustrative/powershell/W25-D5-record-green.ps1
학습용 예시 · W25 phase wrapper · 정본 답안 아님 · 로컬 미실행 · 학습용 예시 · 정본 답안 아님 · NOT_RUN · W25-F1531줄 연결31줄 번역3 chunks
D5 RecordGreen — current selector exact Green과 XML archive
illustrative/powershell/W25-D5-record-green.ps1
학습용 예시 · W25 phase wrapper · 정본 답안 아님 · 로컬 미실행 · 학습용 예시 · 정본 답안 아님 · NOT_RUN · W25-F15STEP 01 / 13
오늘 이 코드에서 해결할 문제
무엇을 이해해야 하는지 질문부터 잡습니다.
native 0·tests=1·failure/error/skip=0을 확인하고 Green XML bytes를 history hash와 결박해 보존한다.
- LearnerGreen은 어느 source와 실제 결과에서 확인해야 할까?
- 첫 실패를 만드는 조건과 fail-closed 지점은 어디일까?
- 왜 ‘700/300 Green은 10_000 finalState나 Q41을 증명하지 않는다’를 별도 경계로 남겨야 할까?
LearnerGreennativeExit=0tests=1status totals=0green-exact.xml왜 필요한가 — D5 RecordGreen — current selector exact Green과 XML archive
-
LearnerGreen가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 native 0·tests=1·failure/error/skip=0을 확인하고 Green XML bytes를 history hash와 결박해 보존한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘700/300 Green은 10_000 finalState나 Q41을 증명하지 않는다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 LearnerGreen와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 02 / 13
아주 짧게: 이 코드는 왜 필요할까?
웹소설 대신 이 코드가 필요한 이유만 두 문단으로 쉽게 봅니다.
사용자의 기본 선택에 따라 이 HTML은 SECURITIES(증권)을 주 트랙으로 읽는다. CARD는 비교용이며 명시적으로 고르면 기본값을 덮어쓸 수 있다. 실제 실행은 최종 선택 한 개를 selected-track.csv·근거·state에 같은 값으로 기록하고 reference와 learner 폴더를 분리한 뒤에만 시작한다. 이 HTML 자체는 Gradle/JUnit을 실행하지 않아 NOT_RUN 상태다.
한 통장만 골라 빨강에서 초록까지 증명하는 일주일
이 파일은 native 0·tests=1·failure/error/skip=0을 확인하고 Green XML bytes를 history hash와 결박해 보존한다. 눈으로 읽을 때는 각 줄을 검수표 한 칸처럼 보고, 입력과 다음 상태를 놓치지 않는다.
마지막 도장은 hash 확인, 세 test phase의 실제 JUnit 실행, XML bytes archive, 사람 review를 서로 구분한 뒤에만 찍는다. Review는 새 test가 아니며 Q41은 stage runtime 밖의 별도 NOT_RUN 과제, sealed official status는 USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED다. 특히 700/300 Green은 10_000 finalState나 Q41을 증명하지 않는다
딱 여기까지만 비유와 SECURITIES 기본 배지는 실제 selected-track 근거, Gradle/JUnit 실행, XML bytes 보존, 사람 review, Q41 실행, sealed official 확인을 대신하지 않는다.
STEP 03 / 13
초등학생도 이해하는 설명
생활 비유와 실제 코드의 경계를 함께 확인합니다.
값 1: LearnerGreen
이 파일에서 계속 확인할 고정 단서가 LearnerGreen다.
- 코드 연결
F15 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- 700/300 Green은 10_000 finalState나 Q41을 증명하지 않는다
값 2: nativeExit=0
이 파일에서 계속 확인할 고정 단서가 nativeExit=0다.
- 코드 연결
F15 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- Red XML과 경로를 공유하면 evidence chain이 끊긴다
값 3: tests=1
이 파일에서 계속 확인할 고정 단서가 tests=1다.
- 코드 연결
F15 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- reference와 learner root는 서로 달라야 한다
값 4: status totals=0
이 파일에서 계속 확인할 고정 단서가 status totals=0다.
- 코드 연결
F15 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
값 5: green-exact.xml
이 파일에서 계속 확인할 고정 단서가 green-exact.xml다.
- 코드 연결
F15 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
STEP 04 / 13
비유 ↔ 코드 전체 연결표
감사 규칙상 연결 대상인 원본 31줄을 빠짐없이 연결합니다.
| 줄 | 정확한 원본 줄 | STARRY 비유 | 실제 뜻·입력·결과·한계 |
|---|---|---|---|
| 1줄F15-L01 | # W25 PDF p32-p37의 current-week one-test Green 흐름을 정리한 학습용 예시다. |
출고표 1번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다.
|
| 2줄F15-L02 | # native exit 0과 exact JUnit tests= |
출고표 2번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다.
|
| 3줄F15-L03 | $ErrorActionPreference = |
출고표 3번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 PowerShell 오류를 계속 진행하지 않고 중단시키는 기본 정책을 둔다.
|
| 4줄F15-L04 | $ReferenceRoot = |
출고표 4번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 입력 경로를 실제 절대 경로로 확인한다.
|
| 5줄F15-L05 | $LearnerRoot = |
출고표 5번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 입력 경로를 실제 절대 경로로 확인한다.
|
| 6줄F15-L06 | if ( |
출고표 6번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 조건·반복·함수의 실행 block을 연다.
|
| 7줄F15-L07 | throw 'reference and learner roots must be different' |
출고표 7번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 8줄F15-L08 | } |
출고표 8번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 10줄F15-L10 | $Verifier = |
출고표 10번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 11줄F15-L11 | & powershell. |
출고표 11번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W25-D5-record-green.ps1의 다음 검증 또는 설명 단계를 구성한다.
|
| 12줄F15-L12 | -ReferenceRoot $ReferenceRoot -LearnerRoot $LearnerRoot -Week 25 -Phase RecordGreen -TimeoutSeconds 1200 |
출고표 12번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 현재 W25 selector 하나를 실행해 exact Green을 기록하는 phase다.
|
| 13줄F15-L13 | if ( |
출고표 13번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 현재 W25 selector 하나를 실행해 exact Green을 기록하는 phase다.
|
| 15줄F15-L15 | $State = |
출고표 15번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 JSON text를 필드로 접근 가능한 PowerShell object로 바꾼다.
|
| 16줄F15-L16 | $Entry = |
출고표 16번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 17줄F15-L17 | $Suites = |
출고표 17번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 18줄F15-L18 | if ( |
출고표 18번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 19줄F15-L19 | if ( |
출고표 19번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 20줄F15-L20 | $Suite = |
출고표 20번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 21줄F15-L21 | if ( |
출고표 21번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 조건·반복·함수의 실행 block을 연다.
|
| 22줄F15-L22 | throw 'Green XML must be tests= |
출고표 22번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 23줄F15-L23 | } |
출고표 23번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 24줄F15-L24 | $Xml = |
출고표 24번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 25줄F15-L25 | $ArchiveDir = |
출고표 25번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 26줄F15-L26 | New-Item -ItemType Directory -Force -Path $ArchiveDir | Out-Null |
출고표 26번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 Markdown 표 또는 PowerShell pipeline에서 값을 열이나 다음 명령으로 연결한다.
|
| 27줄F15-L27 | $Archive = |
출고표 27번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 덮어쓰기 전에 Green JUnit XML bytes를 고유 evidence 경로로 보존한다.
|
| 28줄F15-L28 | $Tmp = |
출고표 28번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 29줄F15-L29 | Copy-Item -LiteralPath $Xml -Destination $Tmp -Force |
출고표 29번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W25-D5-record-green.ps1의 다음 검증 또는 설명 단계를 구성한다.
|
| 30줄F15-L30 | $ArchiveHash = |
출고표 30번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 현재 bytes를 64자리 digest로 evidence에 결박한다.
|
| 31줄F15-L31 | if ( |
출고표 31번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 현재 bytes를 64자리 digest로 evidence에 결박한다.
|
| 32줄F15-L32 | Move-Item -LiteralPath $Tmp -Destination $Archive -Force |
출고표 32번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W25-D5-record-green.ps1의 다음 검증 또는 설명 단계를 구성한다.
|
| 33줄F15-L33 | "W25_CURRENT_GREEN_VERIFIED track= |
출고표 33번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 현재 bytes를 64자리 digest로 evidence에 결박한다.
|
STEP 05 / 13
원본 코드 조각
원본을 3개 의미 조각으로 나누어 그대로 확인합니다.
파일을 한꺼번에 외우지 않고 실행 의미가 이어지는 작은 조각으로 봅니다. 아래 코드는 prompt·fixture·가정을 밝힌 학습용 예시 source이며, 제공 정본 답안이나 실행 결과가 아닌 NOT_RUN 자료입니다.
# W25 PDF p32-p37의 current-week one-test Green 흐름을 정리한 학습용 예시다.
# native exit 0과 exact JUnit tests=1/failures=0/errors=0/skipped=0을 함께 확인한다.
$ErrorActionPreference = 'Stop'
$ReferenceRoot = (Resolve-Path -LiteralPath $env:FINANCIAL_IT_REFERENCE_ROOT).Path
$LearnerRoot = (Resolve-Path -LiteralPath $env:FINANCIAL_IT_LEARNER_ROOT).Path
if ([string]::Equals($ReferenceRoot, $LearnerRoot, [StringComparison]::OrdinalIgnoreCase)) {
throw 'reference and learner roots must be different'
}
$Verifier = Join-Path $ReferenceRoot 'scripts\verify-track-learner-proof.ps1'
& powershell.exe -NoProfile -ExecutionPolicy Bypass -File $Verifier `
-ReferenceRoot $ReferenceRoot -LearnerRoot $LearnerRoot -Week 25 -Phase RecordGreen -TimeoutSeconds 1200
if ($LASTEXITCODE -ne 0) { throw "W25 RecordGreen wrapper exit=$LASTEXITCODE" }
$State = Get-Content -Raw -LiteralPath (Join-Path $LearnerRoot '.track-learning-stage.json') | ConvertFrom-Json
$Entry = @($State.history)[-1]
$Suites = @($Entry.execution.suites)
if ($State.phase -cne 'LearnerGreen' -or $Entry.execution.mode -cne 'Green') { throw 'LearnerGreen state mismatch' }
if ($Entry.execution.nativeExit -ne 0 -or $Suites.Count -ne 1) { throw 'Green must have exit 0 and one suite' }
$Suite = $Suites[0]
if ($Suite.tests -ne 1 -or $Suite.failures -ne 0 -or $Suite.errors -ne 0 -or $Suite.skipped -ne 0) {
throw 'Green XML must be tests=1, failures=0, errors=0, skipped=0'
}
$Xml = Join-Path $LearnerRoot ("build\test-results\test\TEST-{0}.xml" -f $Suite.selector)
$ArchiveDir = Join-Path $LearnerRoot ("evidence\w25\{0}" -f $State.track.ToLowerInvariant())
New-Item -ItemType Directory -Force -Path $ArchiveDir | Out-Null
$Archive = Join-Path $ArchiveDir 'green-exact.xml'
$Tmp = "$Archive.tmp"
Copy-Item -LiteralPath $Xml -Destination $Tmp -Force
$ArchiveHash = (Get-FileHash -LiteralPath $Tmp -Algorithm SHA256).Hash.ToLowerInvariant()
if ($ArchiveHash -cne $Suite.xmlSha256) { throw 'archived Green XML hash differs from runtime history' }
Move-Item -LiteralPath $Tmp -Destination $Archive -Force
"W25_CURRENT_GREEN_VERIFIED track=$($State.track) tests=1 failures=0 errors=0 skipped=0 archived_xml_sha256=$ArchiveHash"
STEP 06 / 13
코드 한 줄씩 한국어로 번역
비어 있지 않은 31줄을 모두 한국어로 옮깁니다.
비어 있지 않은 원본 줄은 하나도 생략하지 않습니다.
| 줄 | 원본 | 한국어 번역 |
|---|---|---|
| 1 | # W25 PDF p32-p37의 current-week one-test Green 흐름을 정리한 학습용 예시다. | 문서 의미: 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다. |
| 2 | # native exit 0과 exact JUnit tests=1/failures=0/errors=0/skipped=0을 함께 확인한다. | 문서 의미: 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다. |
| 3 | $ErrorActionPreference = 'Stop' | 실행 의미: PowerShell 오류를 계속 진행하지 않고 중단시키는 기본 정책을 둔다. |
| 4 | $ReferenceRoot = (Resolve-Path -LiteralPath $env:FINANCIAL_IT_REFERENCE_ROOT).Path | 실행 의미: 입력 경로를 실제 절대 경로로 확인한다. |
| 5 | $LearnerRoot = (Resolve-Path -LiteralPath $env:FINANCIAL_IT_LEARNER_ROOT).Path | 실행 의미: 입력 경로를 실제 절대 경로로 확인한다. |
| 6 | if ([string]::Equals($ReferenceRoot, $LearnerRoot, [StringComparison]::OrdinalIgnoreCase)) { | 실행 의미: 조건·반복·함수의 실행 block을 연다. |
| 7 | throw 'reference and learner roots must be different' | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 8 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 10 | $Verifier = Join-Path $ReferenceRoot 'scripts\verify-track-learner-proof.ps1' | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 11 | & powershell.exe -NoProfile -ExecutionPolicy Bypass -File $Verifier ` | 실행 의미: W25-D5-record-green.ps1의 다음 검증 또는 설명 단계를 구성한다. |
| 12 | -ReferenceRoot $ReferenceRoot -LearnerRoot $LearnerRoot -Week 25 -Phase RecordGreen -TimeoutSeconds 1200 | 실행 의미: 현재 W25 selector 하나를 실행해 exact Green을 기록하는 phase다. |
| 13 | if ($LASTEXITCODE -ne 0) { throw "W25 RecordGreen wrapper exit=$LASTEXITCODE" } | 실행 의미: 현재 W25 selector 하나를 실행해 exact Green을 기록하는 phase다. |
| 15 | $State = Get-Content -Raw -LiteralPath (Join-Path $LearnerRoot '.track-learning-stage.json') | ConvertFrom-Json | 실행 의미: JSON text를 필드로 접근 가능한 PowerShell object로 바꾼다. |
| 16 | $Entry = @($State.history)[-1] | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 17 | $Suites = @($Entry.execution.suites) | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 18 | if ($State.phase -cne 'LearnerGreen' -or $Entry.execution.mode -cne 'Green') { throw 'LearnerGreen state mismatch' } | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 19 | if ($Entry.execution.nativeExit -ne 0 -or $Suites.Count -ne 1) { throw 'Green must have exit 0 and one suite' } | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 20 | $Suite = $Suites[0] | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 21 | if ($Suite.tests -ne 1 -or $Suite.failures -ne 0 -or $Suite.errors -ne 0 -or $Suite.skipped -ne 0) { | 실행 의미: 조건·반복·함수의 실행 block을 연다. |
| 22 | throw 'Green XML must be tests=1, failures=0, errors=0, skipped=0' | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 23 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 24 | $Xml = Join-Path $LearnerRoot ("build\test-results\test\TEST-{0}.xml" -f $Suite.selector) | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 25 | $ArchiveDir = Join-Path $LearnerRoot ("evidence\w25\{0}" -f $State.track.ToLowerInvariant()) | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 26 | New-Item -ItemType Directory -Force -Path $ArchiveDir | Out-Null | 실행 의미: Markdown 표 또는 PowerShell pipeline에서 값을 열이나 다음 명령으로 연결한다. |
| 27 | $Archive = Join-Path $ArchiveDir 'green-exact.xml' | 실행 의미: 덮어쓰기 전에 Green JUnit XML bytes를 고유 evidence 경로로 보존한다. |
| 28 | $Tmp = "$Archive.tmp" | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 29 | Copy-Item -LiteralPath $Xml -Destination $Tmp -Force | 실행 의미: W25-D5-record-green.ps1의 다음 검증 또는 설명 단계를 구성한다. |
| 30 | $ArchiveHash = (Get-FileHash -LiteralPath $Tmp -Algorithm SHA256).Hash.ToLowerInvariant() | 실행 의미: 현재 bytes를 64자리 digest로 evidence에 결박한다. |
| 31 | if ($ArchiveHash -cne $Suite.xmlSha256) { throw 'archived Green XML hash differs from runtime history' } | 실행 의미: 현재 bytes를 64자리 digest로 evidence에 결박한다. |
| 32 | Move-Item -LiteralPath $Tmp -Destination $Archive -Force | 실행 의미: W25-D5-record-green.ps1의 다음 검증 또는 설명 단계를 구성한다. |
| 33 | "W25_CURRENT_GREEN_VERIFIED track=$($State.track) tests=1 failures=0 errors=0 skipped=0 archived_xml_sha256=$ArchiveHash" | 실행 의미: 현재 bytes를 64자리 digest로 evidence에 결박한다. |
STEP 07 / 13
기존 수준의 한 줄 읽기·문법 해부
쉬운 설명 다음에 문법과 실행 순서를 정밀하게 읽습니다.
한 줄로 읽기D5 RecordGreen — current selector exact Green과 XML archive는 native 0·tests=1·failure/error/skip=0을 확인하고 Green XML bytes를 history hash와 결박해 보존한다.
문법 해부
- .ps1 문법에서 선언·조건·pipeline·block 경계를 먼저 나눈다.
- manifest의 finalState와 packaged progressive test의 1_000→700/300 oracle을 서로 다른 계약으로 읽는다.
- phase state·native exit·JUnit XML hash·보존된 XML bytes·사람 판정·USER_ATTESTED external status를 서로 대체하지 않는다.
실행 순서
- 기본 트랙은 SECURITIES(증권)이며, 명시적 CARD 선택은 기본값을 덮어쓴다. 실제 실행 전 최종 선택 한 개를 selected-track.csv·근거·state에 같은 값으로 기록하고 서로 다른 reference/learner root를 확인한다.
- Prepare→VerifyStarter→RecordRed→VerifySolution→RecordGreen→Cumulative→Review 순서를 지킨다.
- test를 소유한 세 phase에서만 native exit와 exact JUnit XML 수치를 판정한다.
- 다음 cleanTest 전에 XML bytes를 고유 경로에 보존하고 runtime history hash와 다시 묶는다. Review·Q41·sealed official evidence는 각자의 별도 owner와 검증 수준으로 남긴다.
W25 조각별 정밀 해설
F15-C01 · 원문 1–12줄
- 문법 해부
- .ps1 문법으로 1–12줄의 선언·조건·phase·assert block을 나눈다.
- 실제 값 추적
- LearnerGreen, nativeExit=0, tests=1를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- 기본 SECURITIES 또는 명시적으로 덮어쓴 CARD 중 최종 선택 한 개의 selected-track evidence와 runtime 결과에서 expected와 actual이 일치하고 owner evidence가 같은 run/hash 및 보존 XML에 연결되는 경우다. 기본/덮어쓰기 표시만 있고 실행 evidence가 없으면 NOT_RUN이다.
- 틀린 예·반례
- 700/300 Green은 10_000 finalState나 Q41을 증명하지 않는다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- phase 이름·manifest finalState·history hash·exit0 하나를 W25 증거 전체와 같다고 보지 않는다.
- 하지 않는 일
- 700/300 Green은 10_000 finalState나 Q41을 증명하지 않는다; Red XML과 경로를 공유하면 evidence chain이 끊긴다; reference와 learner root는 서로 달라야 한다; 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다; 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
- 다음 연결
- 다음 조각 또는 F15 evidence 판정으로 상태를 넘긴다.
F15-C02 · 원문 13–24줄
- 문법 해부
- .ps1 문법으로 13–24줄의 선언·조건·phase·assert block을 나눈다.
- 실제 값 추적
- LearnerGreen, nativeExit=0, tests=1를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- 기본 SECURITIES 또는 명시적으로 덮어쓴 CARD 중 최종 선택 한 개의 selected-track evidence와 runtime 결과에서 expected와 actual이 일치하고 owner evidence가 같은 run/hash 및 보존 XML에 연결되는 경우다. 기본/덮어쓰기 표시만 있고 실행 evidence가 없으면 NOT_RUN이다.
- 틀린 예·반례
- 700/300 Green은 10_000 finalState나 Q41을 증명하지 않는다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- phase 이름·manifest finalState·history hash·exit0 하나를 W25 증거 전체와 같다고 보지 않는다.
- 하지 않는 일
- 700/300 Green은 10_000 finalState나 Q41을 증명하지 않는다; Red XML과 경로를 공유하면 evidence chain이 끊긴다; reference와 learner root는 서로 달라야 한다; 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다; 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
- 다음 연결
- 다음 조각 또는 F15 evidence 판정으로 상태를 넘긴다.
F15-C03 · 원문 25–33줄
- 문법 해부
- .ps1 문법으로 25–33줄의 선언·조건·phase·assert block을 나눈다.
- 실제 값 추적
- LearnerGreen, nativeExit=0, tests=1를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- 기본 SECURITIES 또는 명시적으로 덮어쓴 CARD 중 최종 선택 한 개의 selected-track evidence와 runtime 결과에서 expected와 actual이 일치하고 owner evidence가 같은 run/hash 및 보존 XML에 연결되는 경우다. 기본/덮어쓰기 표시만 있고 실행 evidence가 없으면 NOT_RUN이다.
- 틀린 예·반례
- 700/300 Green은 10_000 finalState나 Q41을 증명하지 않는다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- phase 이름·manifest finalState·history hash·exit0 하나를 W25 증거 전체와 같다고 보지 않는다.
- 하지 않는 일
- 700/300 Green은 10_000 finalState나 Q41을 증명하지 않는다; Red XML과 경로를 공유하면 evidence chain이 끊긴다; reference와 learner root는 서로 달라야 한다; 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다; 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
- 다음 연결
- 다음 조각 또는 F15 evidence 판정으로 상태를 넘긴다.
실행 순서 — D5 RecordGreen — current selector exact Green과 XML archive
-
nativeExit=0가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 native 0·tests=1·failure/error/skip=0을 확인하고 Green XML bytes를 history hash와 결박해 보존한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘Red XML과 경로를 공유하면 evidence chain이 끊긴다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 nativeExit=0와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 08 / 13
실제 값 따라가기
같은 입력값이 어느 줄을 지나 어떤 결과가 되는지 추적합니다.
| 순서 | 들어온 값 | 코드가 하는 일 | 나온 값·상태 | 경계 |
|---|---|---|---|---|
| 입력 | LearnerGreen | source 계약에 대입 | F15 실행/설명 시작 상태 | 700/300 Green은 10_000 finalState나 Q41을 증명하지 않는다 |
| 검증 | nativeExit=0 | expected와 actual 또는 형식 대조 | 통과 또는 첫 mismatch | Red XML과 경로를 공유하면 evidence chain이 끊긴다 |
| 증거 | green-exact.xml | marker·hash·row를 같은 run에 연결 | 범위가 적힌 evidence 후보 | 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다 |
실제 값 — D5 RecordGreen — current selector exact Green과 XML archive
-
tests=1가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 native 0·tests=1·failure/error/skip=0을 확인하고 Green XML bytes를 history hash와 결박해 보존한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘reference와 learner root는 서로 달라야 한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 tests=1와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 09 / 13
Gradle·JUnit XML·PowerShell·SQL 내부에서 벌어지는 일
세 test phase, XML bytes archive, Review, 별도 Q41, USER_ATTESTED sealed 결과의 owner와 증명 범위를 구분합니다.
W25-D5-record-green.ps1 bytes와 track·phase·hash 계약을 읽는다.
SECURITIES 기본 선택과 파일 존재·phase 이름만으로 runtime Green을 주장할 수 없다. 실제 selected-track evidence와 실행 결과는 별도다.RecordRed·RecordGreen·Cumulative에서만 native exit와 exact JUnit XML을 만든다.
700/300 Green은 10_000 finalState나 Q41을 증명하지 않는다XML bytes를 고유 파일로 보존하고 history hash와 묶은 뒤, Review는 기존 CumulativeGreen만 인용한다. Q41은 별도 PostgreSQL evidence, sealed official status는 user-attested evidence로 남긴다.
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다첫 실패 경계 — D5 RecordGreen — current selector exact Green과 XML archive
-
status totals=0가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 native 0·tests=1·failure/error/skip=0을 확인하고 Green XML bytes를 history hash와 결박해 보존한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 status totals=0와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 10 / 13
흔한 착각과 틀린 예
그럴듯하지만 틀린 해석을 반례로 고칩니다.
❌ Prepare·VerifyStarter·VerifySolution·Review도 Gradle을 실행해 Green을 만든다.
왜 틀리나 runtime에서 test 실행을 소유하는 phase는 RecordRed·RecordGreen·Cumulative뿐이다.
바르게 읽기 각 phase history의 execution 유무와 mode를 직접 확인한다.
반례 VerifySolution은 solution hash만 검증하므로 새 JUnit XML이 없어야 정상이다.
❌ 기본 트랙이 SECURITIES이므로 CARD도 함께 실행해도 되고, 기본 배지만으로 runtime 선택·실행 증거가 완성된다.
왜 틀리나 W25 계약은 실제 사용자 근거가 있는 선택 트랙 하나와 반대 트랙 leak 부재를 요구한다.
바르게 읽기 기본 선택은 SECURITIES(증권)이며 명시적 CARD 선택은 덮어쓰기다. 실행 전 최종 선택 한 개를 selected-track.csv·근거·state에 같은 값으로 고정한다.
반례 SECURITIES 기본 배지만 보고 test 실행을 주장하거나 두 트랙 test가 함께 보이면 선택 경계를 위반한다.
❌ progressive_contract Green이면 manifest의 finalState 10_000도 증명된다.
왜 틀리나 packaged test는 1_000에서 300을 처리한 700/300만 assert한다.
바르게 읽기 10_000 finalState는 별도 learner test 또는 사람이 결박한 evidence로 증명한다.
반례 runtime은 domainContract.finalState 문자열을 parse하거나 assert하지 않는다.
❌ history에 XML SHA가 있으니 Red·Green·Cumulative XML 원본이 모두 보존됐다.
왜 틀리나 다음 cleanTest가 build/test-results의 이전 XML을 덮어쓰며 state는 bytes를 복사하지 않는다.
바르게 읽기 각 phase 직후 고유 evidence 경로로 원자 복사하고 hash를 history와 대조한다.
반례 RecordGreen 뒤에는 Red XML 경로가 사라질 수 있다.
❌ Review가 새 test를 실행해 CumulativeGreen을 다시 만들고 Q41·sealed official 결과까지 자동 확인한다.
왜 틀리나 Review는 기존 CumulativeGreen을 전제로 review entry와 leak check만 기록한다. Q41은 별도 PostgreSQL 과제이고 sealed official status는 user-attested다.
바르게 읽기 Review에서는 reviewedPhase와 history 증가만 보고, Q41 native evidence와 USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED sealed evidence를 별도로 판정한다.
반례 Review 뒤 phase는 여전히 CumulativeGreen이고 새 execution/XML·Q41 transcript·official login verification이 생기지 않는다.
STEP 11 / 13
이 코드가 보장하지 않는 것
선택 미결정·10_000 finalState·XML 보존·Review/Q41/sealed official truth처럼 이 코드가 책임지지 않는 일을 분리합니다.
700/300 Green은 10_000 finalState나 Q41을 증명하지 않는다
이 책임을 맡는 곳: runtime GateRed XML과 경로를 공유하면 evidence chain이 끊긴다
이 책임을 맡는 곳: external/human reviewreference와 learner root는 서로 달라야 한다
이 책임을 맡는 곳: release manifest기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
이 책임을 맡는 곳: 운영 환경증명하지 않는 범위 — D5 RecordGreen — current selector exact Green과 XML archive
-
green-exact.xml가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 native 0·tests=1·failure/error/skip=0을 확인하고 Green XML bytes를 history hash와 결박해 보존한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 green-exact.xml와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 12 / 13
직접 다시 써보기
뜻 → 조각 → 전체 코드 순서로 다시 씁니다.
1단계 · 뜻부터 복원
- native 0·tests=1·failure/error/skip=0을 확인하고 Green XML bytes를 history hash와 결박해 보존한다.
- 핵심 값은 LearnerGreen, nativeExit=0, tests=1, status totals=0, green-exact.xml다.
2단계 · 코드 조각 재조립
- 1. 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다
- 2. 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다
- 3. PowerShell 오류를 계속 진행하지 않고 중단시키는 기본 정책을 둔다
- 4. 입력 경로를 실제 절대 경로로 확인한다
- 5. 입력 경로를 실제 절대 경로로 확인한다
- 6. 조건·반복·함수의 실행 block을 연다
- 7. 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다
- 8. 앞에서 연 block 또는 호출 범위를 닫는다
3단계 · 파일 전체 다시 쓰기
illustrative/powershell/W25-D5-record-green.ps1을 새 파일에 다시 쓰고 expected·actual·실패·cleanup·비범위를 주석으로 표시한다.
자가 점검
- 비어 있지 않은 모든 source 줄을 한 번씩 읽었나?
- 기본 트랙을 SECURITIES(증권) 하나로 두고 기본 선택·selected-track evidence·runtime Green을 서로 분리했나?
- Review·Q41·USER_ATTESTED sealed 상태를 자동 성공으로 꾸미지 않았나?
- XML bytes archive와 첫 실패·cleanup 책임을 설명할 수 있나?
STEP 13 / 13
전체 원본 source
감사로 고정한 전체 source를 가감 없이 확인합니다.
학습용 예시 전체 확인하기 · 정본 답안 아님 · NOT_RUN
# W25 PDF p32-p37의 current-week one-test Green 흐름을 정리한 학습용 예시다.
# native exit 0과 exact JUnit tests=1/failures=0/errors=0/skipped=0을 함께 확인한다.
$ErrorActionPreference = 'Stop'
$ReferenceRoot = (Resolve-Path -LiteralPath $env:FINANCIAL_IT_REFERENCE_ROOT).Path
$LearnerRoot = (Resolve-Path -LiteralPath $env:FINANCIAL_IT_LEARNER_ROOT).Path
if ([string]::Equals($ReferenceRoot, $LearnerRoot, [StringComparison]::OrdinalIgnoreCase)) {
throw 'reference and learner roots must be different'
}
$Verifier = Join-Path $ReferenceRoot 'scripts\verify-track-learner-proof.ps1'
& powershell.exe -NoProfile -ExecutionPolicy Bypass -File $Verifier `
-ReferenceRoot $ReferenceRoot -LearnerRoot $LearnerRoot -Week 25 -Phase RecordGreen -TimeoutSeconds 1200
if ($LASTEXITCODE -ne 0) { throw "W25 RecordGreen wrapper exit=$LASTEXITCODE" }
$State = Get-Content -Raw -LiteralPath (Join-Path $LearnerRoot '.track-learning-stage.json') | ConvertFrom-Json
$Entry = @($State.history)[-1]
$Suites = @($Entry.execution.suites)
if ($State.phase -cne 'LearnerGreen' -or $Entry.execution.mode -cne 'Green') { throw 'LearnerGreen state mismatch' }
if ($Entry.execution.nativeExit -ne 0 -or $Suites.Count -ne 1) { throw 'Green must have exit 0 and one suite' }
$Suite = $Suites[0]
if ($Suite.tests -ne 1 -or $Suite.failures -ne 0 -or $Suite.errors -ne 0 -or $Suite.skipped -ne 0) {
throw 'Green XML must be tests=1, failures=0, errors=0, skipped=0'
}
$Xml = Join-Path $LearnerRoot ("build\test-results\test\TEST-{0}.xml" -f $Suite.selector)
$ArchiveDir = Join-Path $LearnerRoot ("evidence\w25\{0}" -f $State.track.ToLowerInvariant())
New-Item -ItemType Directory -Force -Path $ArchiveDir | Out-Null
$Archive = Join-Path $ArchiveDir 'green-exact.xml'
$Tmp = "$Archive.tmp"
Copy-Item -LiteralPath $Xml -Destination $Tmp -Force
$ArchiveHash = (Get-FileHash -LiteralPath $Tmp -Algorithm SHA256).Hash.ToLowerInvariant()
if ($ArchiveHash -cne $Suite.xmlSha256) { throw 'archived Green XML hash differs from runtime history' }
Move-Item -LiteralPath $Tmp -Destination $Archive -Force
"W25_CURRENT_GREEN_VERIFIED track=$($State.track) tests=1 failures=0 errors=0 skipped=0 archived_xml_sha256=$ArchiveHash"
16W25-SQL-Q41 — balance snapshot과 opening 포함 ledger sum 대사
illustrative/sql/W25-SQL-Q41.sql
학습용 예시 · W25-SQL-Q41 prompt 기반 · 정본 답안 아님 · workbook 제공 정답 아님 · 학습용 예시 · 정본 답안 아님 · NOT_RUN · W25-F1630줄 연결30줄 번역3 chunks
W25-SQL-Q41 — balance snapshot과 opening 포함 ledger sum 대사
illustrative/sql/W25-SQL-Q41.sql
학습용 예시 · W25-SQL-Q41 prompt 기반 · 정본 답안 아님 · workbook 제공 정답 아님 · 학습용 예시 · 정본 답안 아님 · NOT_RUN · W25-F16STEP 01 / 13
오늘 이 코드에서 해결할 문제
무엇을 이해해야 하는지 질문부터 잡습니다.
account 한 행과 opening entry를 포함한 ledger_entry 합계를 계좌별로 비교해 mismatch 계좌만 반환하는 학습용 query를 보여 준다.
- account grain은 어느 source와 실제 결과에서 확인해야 할까?
- 첫 실패를 만드는 조건과 fail-closed 지점은 어디일까?
- 왜 ‘PDF는 prompt만 주며 workbook 제공 정답이 아니다’를 별도 경계로 남겨야 할까?
account grainSUM(signed_amount)LEFT JOINCOALESCE(...,0)current fixture expected rows=2왜 필요한가 — W25-SQL-Q41 — balance snapshot과 opening 포함 ledger sum 대사
-
account grain가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 account 한 행과 opening entry를 포함한 ledger_entry 합계를 계좌별로 비교해 mismatch 계좌만 반환하는 학습용 query를 보여 준다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘PDF는 prompt만 주며 workbook 제공 정답이 아니다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 account grain와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 02 / 13
아주 짧게: 이 코드는 왜 필요할까?
웹소설 대신 이 코드가 필요한 이유만 두 문단으로 쉽게 봅니다.
사용자의 기본 선택에 따라 이 HTML은 SECURITIES(증권)을 주 트랙으로 읽는다. CARD는 비교용이며 명시적으로 고르면 기본값을 덮어쓸 수 있다. 실제 실행은 최종 선택 한 개를 selected-track.csv·근거·state에 같은 값으로 기록하고 reference와 learner 폴더를 분리한 뒤에만 시작한다. 이 HTML 자체는 Gradle/JUnit을 실행하지 않아 NOT_RUN 상태다.
한 통장만 골라 빨강에서 초록까지 증명하는 일주일
이 파일은 account 한 행과 opening entry를 포함한 ledger_entry 합계를 계좌별로 비교해 mismatch 계좌만 반환하는 학습용 query를 보여 준다. 눈으로 읽을 때는 각 줄을 검수표 한 칸처럼 보고, 입력과 다음 상태를 놓치지 않는다.
마지막 도장은 hash 확인, 세 test phase의 실제 JUnit 실행, XML bytes archive, 사람 review를 서로 구분한 뒤에만 찍는다. Review는 새 test가 아니며 Q41은 stage runtime 밖의 별도 NOT_RUN 과제, sealed official status는 USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED다. 특히 PDF는 prompt만 주며 workbook 제공 정답이 아니다
딱 여기까지만 비유와 SECURITIES 기본 배지는 실제 selected-track 근거, Gradle/JUnit 실행, XML bytes 보존, 사람 review, Q41 실행, sealed official 확인을 대신하지 않는다.
STEP 03 / 13
초등학생도 이해하는 설명
생활 비유와 실제 코드의 경계를 함께 확인합니다.
값 1: account grain
이 파일에서 계속 확인할 고정 단서가 account grain다.
- 코드 연결
F16 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- PDF는 prompt만 주며 workbook 제공 정답이 아니다
값 2: SUM(signed_amount)
이 파일에서 계속 확인할 고정 단서가 SUM(signed_amount)다.
- 코드 연결
F16 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- RecordGreen runtime은 PostgreSQL/Q41을 실행하지 않는다
값 3: LEFT JOIN
이 파일에서 계속 확인할 고정 단서가 LEFT JOIN다.
- 코드 연결
F16 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- 실제 psql transcript/hash가 별도 필요하다
값 4: COALESCE(...,0)
이 파일에서 계속 확인할 고정 단서가 COALESCE(...,0)다.
- 코드 연결
F16 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- reference와 learner root는 서로 달라야 한다
값 5: current fixture expected rows=2
이 파일에서 계속 확인할 고정 단서가 current fixture expected rows=2다.
- 코드 연결
F16 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
STEP 04 / 13
비유 ↔ 코드 전체 연결표
감사 규칙상 연결 대상인 원본 30줄을 빠짐없이 연결합니다.
| 줄 | 정확한 원본 줄 | STARRY 비유 | 실제 뜻·입력·결과·한계 |
|---|---|---|---|
| 1줄F16-L01 | -- W25-SQL-Q41 학습용 예시이며 workbook 제공 정답이 아니다. |
출고표 1번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W25-SQL-Q41.sql의 다음 검증 또는 설명 단계를 구성한다.
|
| 2줄F16-L02 | -- 입력 grain: |
출고표 2번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W25-SQL-Q41.sql의 다음 검증 또는 설명 단계를 구성한다.
|
| 3줄F16-L03 | -- 출력 grain: |
출고표 3번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W25-SQL-Q41.sql의 다음 검증 또는 설명 단계를 구성한다.
|
| 4줄F16-L04 | WITH ledger_by_account AS ( |
출고표 4번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 opening entry를 포함한 원장 증감액을 계좌별로 먼저 합산한다.
|
| 5줄F16-L05 | SELECT |
출고표 5번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 SQL 집합의 입력·변환·필터 단계를 선언한다.
|
| 6줄F16-L06 | le. |
출고표 6번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W25-SQL-Q41.sql의 다음 검증 또는 설명 단계를 구성한다.
|
| 7줄F16-L07 | SUM( |
출고표 7번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W25-SQL-Q41.sql의 다음 검증 또는 설명 단계를 구성한다.
|
| 8줄F16-L08 | FROM ledger_entry AS le |
출고표 8번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 SQL 집합의 입력·변환·필터 단계를 선언한다.
|
| 9줄F16-L09 | GROUP BY le. |
출고표 9번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W25-SQL-Q41.sql의 다음 검증 또는 설명 단계를 구성한다.
|
| 10줄F16-L10 | ), |
출고표 10번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W25-SQL-Q41.sql의 다음 검증 또는 설명 단계를 구성한다.
|
| 11줄F16-L11 | reconciled AS ( |
출고표 11번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W25-SQL-Q41.sql의 다음 검증 또는 설명 단계를 구성한다.
|
| 12줄F16-L12 | SELECT |
출고표 12번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 SQL 집합의 입력·변환·필터 단계를 선언한다.
|
| 13줄F16-L13 | a. |
출고표 13번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W25-SQL-Q41.sql의 다음 검증 또는 설명 단계를 구성한다.
|
| 14줄F16-L14 | a. |
출고표 14번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W25-SQL-Q41.sql의 다음 검증 또는 설명 단계를 구성한다.
|
| 15줄F16-L15 | COALESCE( |
출고표 15번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 원장 행이 없는 계좌의 합계를 0으로 바꾸어 LEFT JOIN 결과를 보존한다.
|
| 16줄F16-L16 | a. |
출고표 16번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 원장 행이 없는 계좌의 합계를 0으로 바꾸어 LEFT JOIN 결과를 보존한다.
|
| 17줄F16-L17 | FROM account AS a |
출고표 17번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 SQL 집합의 입력·변환·필터 단계를 선언한다.
|
| 18줄F16-L18 | LEFT JOIN ledger_by_account AS l |
출고표 18번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 opening entry를 포함한 원장 증감액을 계좌별로 먼저 합산한다.
|
| 19줄F16-L19 | ON l. |
출고표 19번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W25-SQL-Q41.sql의 다음 검증 또는 설명 단계를 구성한다.
|
| 20줄F16-L20 | ) |
출고표 20번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 21줄F16-L21 | SELECT |
출고표 21번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 SQL 집합의 입력·변환·필터 단계를 선언한다.
|
| 22줄F16-L22 | account_id, |
출고표 22번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W25-SQL-Q41.sql의 다음 검증 또는 설명 단계를 구성한다.
|
| 23줄F16-L23 | snapshot_balance, |
출고표 23번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W25-SQL-Q41.sql의 다음 검증 또는 설명 단계를 구성한다.
|
| 24줄F16-L24 | ledger_sum, |
출고표 24번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W25-SQL-Q41.sql의 다음 검증 또는 설명 단계를 구성한다.
|
| 25줄F16-L25 | difference |
출고표 25번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W25-SQL-Q41.sql의 다음 검증 또는 설명 단계를 구성한다.
|
| 26줄F16-L26 | FROM reconciled |
출고표 26번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 SQL 집합의 입력·변환·필터 단계를 선언한다.
|
| 27줄F16-L27 | WHERE difference <> 0 |
출고표 27번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 SQL 집합의 입력·변환·필터 단계를 선언한다.
|
| 28줄F16-L28 | ORDER BY account_id; |
출고표 28번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 출력 또는 window 계산 순서를 안정적으로 정한다.
|
| 30줄F16-L30 | -- opening entry 반례: |
출고표 30번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W25-SQL-Q41.sql의 다음 검증 또는 설명 단계를 구성한다.
|
| 31줄F16-L31 | -- 원장 0건 반례: |
출고표 31번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 원장 행이 없는 계좌의 합계를 0으로 바꾸어 LEFT JOIN 결과를 보존한다.
|
STEP 05 / 13
원본 코드 조각
원본을 3개 의미 조각으로 나누어 그대로 확인합니다.
파일을 한꺼번에 외우지 않고 실행 의미가 이어지는 작은 조각으로 봅니다. 아래 코드는 prompt·fixture·가정을 밝힌 학습용 예시 source이며, 제공 정본 답안이나 실행 결과가 아닌 NOT_RUN 자료입니다.
-- W25-SQL-Q41 학습용 예시이며 workbook 제공 정답이 아니다.
-- 입력 grain: account 한 행은 계좌 snapshot, ledger_entry 한 행은 원장 증감 한 건이다.
-- 출력 grain: snapshot과 opening 포함 원장 합계가 다른 계좌 한 행. 현재 fixture 예상 행 수는 2다.
WITH ledger_by_account AS (
SELECT
le.account_id,
SUM(le.signed_amount) AS ledger_sum
FROM ledger_entry AS le
GROUP BY le.account_id
),
reconciled AS (
SELECT
a.account_id,
a.balance AS snapshot_balance,
COALESCE(l.ledger_sum, 0) AS ledger_sum,
a.balance - COALESCE(l.ledger_sum, 0) AS difference
FROM account AS a
LEFT JOIN ledger_by_account AS l
ON l.account_id = a.account_id
)
SELECT
account_id,
snapshot_balance,
ledger_sum,
difference
FROM reconciled
WHERE difference <> 0
ORDER BY account_id;
-- opening entry 반례: opening을 제외하면 정상 계좌도 거짓 mismatch가 된다.
-- 원장 0건 반례: LEFT JOIN과 COALESCE로 balance=0 계좌는 difference=0, 양수 snapshot은 mismatch로 남는다.
STEP 06 / 13
코드 한 줄씩 한국어로 번역
비어 있지 않은 30줄을 모두 한국어로 옮깁니다.
비어 있지 않은 원본 줄은 하나도 생략하지 않습니다.
| 줄 | 원본 | 한국어 번역 |
|---|---|---|
| 1 | -- W25-SQL-Q41 학습용 예시이며 workbook 제공 정답이 아니다. | 실행 의미: W25-SQL-Q41.sql의 다음 검증 또는 설명 단계를 구성한다. |
| 2 | -- 입력 grain: account 한 행은 계좌 snapshot, ledger_entry 한 행은 원장 증감 한 건이다. | 실행 의미: W25-SQL-Q41.sql의 다음 검증 또는 설명 단계를 구성한다. |
| 3 | -- 출력 grain: snapshot과 opening 포함 원장 합계가 다른 계좌 한 행. 현재 fixture 예상 행 수는 2다. | 실행 의미: W25-SQL-Q41.sql의 다음 검증 또는 설명 단계를 구성한다. |
| 4 | WITH ledger_by_account AS ( | 실행 의미: opening entry를 포함한 원장 증감액을 계좌별로 먼저 합산한다. |
| 5 | SELECT | 실행 의미: SQL 집합의 입력·변환·필터 단계를 선언한다. |
| 6 | le.account_id, | 실행 의미: W25-SQL-Q41.sql의 다음 검증 또는 설명 단계를 구성한다. |
| 7 | SUM(le.signed_amount) AS ledger_sum | 실행 의미: W25-SQL-Q41.sql의 다음 검증 또는 설명 단계를 구성한다. |
| 8 | FROM ledger_entry AS le | 실행 의미: SQL 집합의 입력·변환·필터 단계를 선언한다. |
| 9 | GROUP BY le.account_id | 실행 의미: W25-SQL-Q41.sql의 다음 검증 또는 설명 단계를 구성한다. |
| 10 | ), | 실행 의미: W25-SQL-Q41.sql의 다음 검증 또는 설명 단계를 구성한다. |
| 11 | reconciled AS ( | 실행 의미: W25-SQL-Q41.sql의 다음 검증 또는 설명 단계를 구성한다. |
| 12 | SELECT | 실행 의미: SQL 집합의 입력·변환·필터 단계를 선언한다. |
| 13 | a.account_id, | 실행 의미: W25-SQL-Q41.sql의 다음 검증 또는 설명 단계를 구성한다. |
| 14 | a.balance AS snapshot_balance, | 실행 의미: W25-SQL-Q41.sql의 다음 검증 또는 설명 단계를 구성한다. |
| 15 | COALESCE(l.ledger_sum, 0) AS ledger_sum, | 실행 의미: 원장 행이 없는 계좌의 합계를 0으로 바꾸어 LEFT JOIN 결과를 보존한다. |
| 16 | a.balance - COALESCE(l.ledger_sum, 0) AS difference | 실행 의미: 원장 행이 없는 계좌의 합계를 0으로 바꾸어 LEFT JOIN 결과를 보존한다. |
| 17 | FROM account AS a | 실행 의미: SQL 집합의 입력·변환·필터 단계를 선언한다. |
| 18 | LEFT JOIN ledger_by_account AS l | 실행 의미: opening entry를 포함한 원장 증감액을 계좌별로 먼저 합산한다. |
| 19 | ON l.account_id = a.account_id | 실행 의미: W25-SQL-Q41.sql의 다음 검증 또는 설명 단계를 구성한다. |
| 20 | ) | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 21 | SELECT | 실행 의미: SQL 집합의 입력·변환·필터 단계를 선언한다. |
| 22 | account_id, | 실행 의미: W25-SQL-Q41.sql의 다음 검증 또는 설명 단계를 구성한다. |
| 23 | snapshot_balance, | 실행 의미: W25-SQL-Q41.sql의 다음 검증 또는 설명 단계를 구성한다. |
| 24 | ledger_sum, | 실행 의미: W25-SQL-Q41.sql의 다음 검증 또는 설명 단계를 구성한다. |
| 25 | difference | 실행 의미: W25-SQL-Q41.sql의 다음 검증 또는 설명 단계를 구성한다. |
| 26 | FROM reconciled | 실행 의미: SQL 집합의 입력·변환·필터 단계를 선언한다. |
| 27 | WHERE difference <> 0 | 실행 의미: SQL 집합의 입력·변환·필터 단계를 선언한다. |
| 28 | ORDER BY account_id; | 실행 의미: 출력 또는 window 계산 순서를 안정적으로 정한다. |
| 30 | -- opening entry 반례: opening을 제외하면 정상 계좌도 거짓 mismatch가 된다. | 실행 의미: W25-SQL-Q41.sql의 다음 검증 또는 설명 단계를 구성한다. |
| 31 | -- 원장 0건 반례: LEFT JOIN과 COALESCE로 balance=0 계좌는 difference=0, 양수 snapshot은 mismatch로 남는다. | 실행 의미: 원장 행이 없는 계좌의 합계를 0으로 바꾸어 LEFT JOIN 결과를 보존한다. |
STEP 07 / 13
기존 수준의 한 줄 읽기·문법 해부
쉬운 설명 다음에 문법과 실행 순서를 정밀하게 읽습니다.
한 줄로 읽기W25-SQL-Q41 — balance snapshot과 opening 포함 ledger sum 대사는 account 한 행과 opening entry를 포함한 ledger_entry 합계를 계좌별로 비교해 mismatch 계좌만 반환하는 학습용 query를 보여 준다.
문법 해부
- .sql 문법에서 선언·조건·pipeline·block 경계를 먼저 나눈다.
- manifest의 finalState와 packaged progressive test의 1_000→700/300 oracle을 서로 다른 계약으로 읽는다.
- phase state·native exit·JUnit XML hash·보존된 XML bytes·사람 판정·USER_ATTESTED external status를 서로 대체하지 않는다.
실행 순서
- 기본 트랙은 SECURITIES(증권)이며, 명시적 CARD 선택은 기본값을 덮어쓴다. 실제 실행 전 최종 선택 한 개를 selected-track.csv·근거·state에 같은 값으로 기록하고 서로 다른 reference/learner root를 확인한다.
- Prepare→VerifyStarter→RecordRed→VerifySolution→RecordGreen→Cumulative→Review 순서를 지킨다.
- test를 소유한 세 phase에서만 native exit와 exact JUnit XML 수치를 판정한다.
- 다음 cleanTest 전에 XML bytes를 고유 경로에 보존하고 runtime history hash와 다시 묶는다. Review·Q41·sealed official evidence는 각자의 별도 owner와 검증 수준으로 남긴다.
W25 조각별 정밀 해설
F16-C01 · 원문 1–12줄
- 문법 해부
- .sql 문법으로 1–12줄의 선언·조건·phase·assert block을 나눈다.
- 실제 값 추적
- account grain, SUM(signed_amount), LEFT JOIN를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- 기본 SECURITIES 또는 명시적으로 덮어쓴 CARD 중 최종 선택 한 개의 selected-track evidence와 runtime 결과에서 expected와 actual이 일치하고 owner evidence가 같은 run/hash 및 보존 XML에 연결되는 경우다. 기본/덮어쓰기 표시만 있고 실행 evidence가 없으면 NOT_RUN이다.
- 틀린 예·반례
- PDF는 prompt만 주며 workbook 제공 정답이 아니다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- phase 이름·manifest finalState·history hash·exit0 하나를 W25 증거 전체와 같다고 보지 않는다.
- 하지 않는 일
- PDF는 prompt만 주며 workbook 제공 정답이 아니다; RecordGreen runtime은 PostgreSQL/Q41을 실행하지 않는다; 실제 psql transcript/hash가 별도 필요하다; reference와 learner root는 서로 달라야 한다; 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다; 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
- 다음 연결
- 다음 조각 또는 F16 evidence 판정으로 상태를 넘긴다.
F16-C02 · 원문 13–24줄
- 문법 해부
- .sql 문법으로 13–24줄의 선언·조건·phase·assert block을 나눈다.
- 실제 값 추적
- account grain, SUM(signed_amount), LEFT JOIN를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- 기본 SECURITIES 또는 명시적으로 덮어쓴 CARD 중 최종 선택 한 개의 selected-track evidence와 runtime 결과에서 expected와 actual이 일치하고 owner evidence가 같은 run/hash 및 보존 XML에 연결되는 경우다. 기본/덮어쓰기 표시만 있고 실행 evidence가 없으면 NOT_RUN이다.
- 틀린 예·반례
- PDF는 prompt만 주며 workbook 제공 정답이 아니다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- phase 이름·manifest finalState·history hash·exit0 하나를 W25 증거 전체와 같다고 보지 않는다.
- 하지 않는 일
- PDF는 prompt만 주며 workbook 제공 정답이 아니다; RecordGreen runtime은 PostgreSQL/Q41을 실행하지 않는다; 실제 psql transcript/hash가 별도 필요하다; reference와 learner root는 서로 달라야 한다; 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다; 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
- 다음 연결
- 다음 조각 또는 F16 evidence 판정으로 상태를 넘긴다.
F16-C03 · 원문 25–31줄
- 문법 해부
- .sql 문법으로 25–31줄의 선언·조건·phase·assert block을 나눈다.
- 실제 값 추적
- account grain, SUM(signed_amount), LEFT JOIN를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- 기본 SECURITIES 또는 명시적으로 덮어쓴 CARD 중 최종 선택 한 개의 selected-track evidence와 runtime 결과에서 expected와 actual이 일치하고 owner evidence가 같은 run/hash 및 보존 XML에 연결되는 경우다. 기본/덮어쓰기 표시만 있고 실행 evidence가 없으면 NOT_RUN이다.
- 틀린 예·반례
- PDF는 prompt만 주며 workbook 제공 정답이 아니다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- phase 이름·manifest finalState·history hash·exit0 하나를 W25 증거 전체와 같다고 보지 않는다.
- 하지 않는 일
- PDF는 prompt만 주며 workbook 제공 정답이 아니다; RecordGreen runtime은 PostgreSQL/Q41을 실행하지 않는다; 실제 psql transcript/hash가 별도 필요하다; reference와 learner root는 서로 달라야 한다; 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다; 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
- 다음 연결
- 다음 조각 또는 F16 evidence 판정으로 상태를 넘긴다.
실행 순서 — W25-SQL-Q41 — balance snapshot과 opening 포함 ledger sum 대사
-
SUM(signed_amount)가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 account 한 행과 opening entry를 포함한 ledger_entry 합계를 계좌별로 비교해 mismatch 계좌만 반환하는 학습용 query를 보여 준다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘RecordGreen runtime은 PostgreSQL/Q41을 실행하지 않는다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 SUM(signed_amount)와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 08 / 13
실제 값 따라가기
같은 입력값이 어느 줄을 지나 어떤 결과가 되는지 추적합니다.
| 순서 | 들어온 값 | 코드가 하는 일 | 나온 값·상태 | 경계 |
|---|---|---|---|---|
| 입력 | account grain | source 계약에 대입 | F16 실행/설명 시작 상태 | PDF는 prompt만 주며 workbook 제공 정답이 아니다 |
| 검증 | SUM(signed_amount) | expected와 actual 또는 형식 대조 | 통과 또는 첫 mismatch | RecordGreen runtime은 PostgreSQL/Q41을 실행하지 않는다 |
| 증거 | current fixture expected rows=2 | marker·hash·row를 같은 run에 연결 | 범위가 적힌 evidence 후보 | 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다 |
실제 값 — W25-SQL-Q41 — balance snapshot과 opening 포함 ledger sum 대사
-
LEFT JOIN가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 account 한 행과 opening entry를 포함한 ledger_entry 합계를 계좌별로 비교해 mismatch 계좌만 반환하는 학습용 query를 보여 준다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘실제 psql transcript/hash가 별도 필요하다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 LEFT JOIN와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 09 / 13
Gradle·JUnit XML·PowerShell·SQL 내부에서 벌어지는 일
세 test phase, XML bytes archive, Review, 별도 Q41, USER_ATTESTED sealed 결과의 owner와 증명 범위를 구분합니다.
W25-SQL-Q41.sql bytes와 track·phase·hash 계약을 읽는다.
SECURITIES 기본 선택과 파일 존재·phase 이름만으로 runtime Green을 주장할 수 없다. 실제 selected-track evidence와 실행 결과는 별도다.RecordRed·RecordGreen·Cumulative에서만 native exit와 exact JUnit XML을 만든다.
PDF는 prompt만 주며 workbook 제공 정답이 아니다XML bytes를 고유 파일로 보존하고 history hash와 묶은 뒤, Review는 기존 CumulativeGreen만 인용한다. Q41은 별도 PostgreSQL evidence, sealed official status는 user-attested evidence로 남긴다.
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다첫 실패 경계 — W25-SQL-Q41 — balance snapshot과 opening 포함 ledger sum 대사
-
COALESCE(...,0)가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 account 한 행과 opening entry를 포함한 ledger_entry 합계를 계좌별로 비교해 mismatch 계좌만 반환하는 학습용 query를 보여 준다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘reference와 learner root는 서로 달라야 한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 COALESCE(...,0)와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 10 / 13
흔한 착각과 틀린 예
그럴듯하지만 틀린 해석을 반례로 고칩니다.
❌ Prepare·VerifyStarter·VerifySolution·Review도 Gradle을 실행해 Green을 만든다.
왜 틀리나 runtime에서 test 실행을 소유하는 phase는 RecordRed·RecordGreen·Cumulative뿐이다.
바르게 읽기 각 phase history의 execution 유무와 mode를 직접 확인한다.
반례 VerifySolution은 solution hash만 검증하므로 새 JUnit XML이 없어야 정상이다.
❌ 기본 트랙이 SECURITIES이므로 CARD도 함께 실행해도 되고, 기본 배지만으로 runtime 선택·실행 증거가 완성된다.
왜 틀리나 W25 계약은 실제 사용자 근거가 있는 선택 트랙 하나와 반대 트랙 leak 부재를 요구한다.
바르게 읽기 기본 선택은 SECURITIES(증권)이며 명시적 CARD 선택은 덮어쓰기다. 실행 전 최종 선택 한 개를 selected-track.csv·근거·state에 같은 값으로 고정한다.
반례 SECURITIES 기본 배지만 보고 test 실행을 주장하거나 두 트랙 test가 함께 보이면 선택 경계를 위반한다.
❌ progressive_contract Green이면 manifest의 finalState 10_000도 증명된다.
왜 틀리나 packaged test는 1_000에서 300을 처리한 700/300만 assert한다.
바르게 읽기 10_000 finalState는 별도 learner test 또는 사람이 결박한 evidence로 증명한다.
반례 runtime은 domainContract.finalState 문자열을 parse하거나 assert하지 않는다.
❌ history에 XML SHA가 있으니 Red·Green·Cumulative XML 원본이 모두 보존됐다.
왜 틀리나 다음 cleanTest가 build/test-results의 이전 XML을 덮어쓰며 state는 bytes를 복사하지 않는다.
바르게 읽기 각 phase 직후 고유 evidence 경로로 원자 복사하고 hash를 history와 대조한다.
반례 RecordGreen 뒤에는 Red XML 경로가 사라질 수 있다.
❌ Review가 새 test를 실행해 CumulativeGreen을 다시 만들고 Q41·sealed official 결과까지 자동 확인한다.
왜 틀리나 Review는 기존 CumulativeGreen을 전제로 review entry와 leak check만 기록한다. Q41은 별도 PostgreSQL 과제이고 sealed official status는 user-attested다.
바르게 읽기 Review에서는 reviewedPhase와 history 증가만 보고, Q41 native evidence와 USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED sealed evidence를 별도로 판정한다.
반례 Review 뒤 phase는 여전히 CumulativeGreen이고 새 execution/XML·Q41 transcript·official login verification이 생기지 않는다.
STEP 11 / 13
이 코드가 보장하지 않는 것
선택 미결정·10_000 finalState·XML 보존·Review/Q41/sealed official truth처럼 이 코드가 책임지지 않는 일을 분리합니다.
PDF는 prompt만 주며 workbook 제공 정답이 아니다
이 책임을 맡는 곳: runtime GateRecordGreen runtime은 PostgreSQL/Q41을 실행하지 않는다
이 책임을 맡는 곳: external/human review실제 psql transcript/hash가 별도 필요하다
이 책임을 맡는 곳: release manifestreference와 learner root는 서로 달라야 한다
이 책임을 맡는 곳: 운영 환경증명하지 않는 범위 — W25-SQL-Q41 — balance snapshot과 opening 포함 ledger sum 대사
-
current fixture expected rows=2가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 account 한 행과 opening entry를 포함한 ledger_entry 합계를 계좌별로 비교해 mismatch 계좌만 반환하는 학습용 query를 보여 준다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 current fixture expected rows=2와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 12 / 13
직접 다시 써보기
뜻 → 조각 → 전체 코드 순서로 다시 씁니다.
1단계 · 뜻부터 복원
- account 한 행과 opening entry를 포함한 ledger_entry 합계를 계좌별로 비교해 mismatch 계좌만 반환하는 학습용 query를 보여 준다.
- 핵심 값은 account grain, SUM(signed_amount), LEFT JOIN, COALESCE(...,0), current fixture expected rows=2다.
2단계 · 코드 조각 재조립
- 1. W25-SQL-Q41.sql의 다음 검증 또는 설명 단계를 구성한다
- 2. W25-SQL-Q41.sql의 다음 검증 또는 설명 단계를 구성한다
- 3. W25-SQL-Q41.sql의 다음 검증 또는 설명 단계를 구성한다
- 4. opening entry를 포함한 원장 증감액을 계좌별로 먼저 합산한다
- 5. SQL 집합의 입력·변환·필터 단계를 선언한다
- 6. W25-SQL-Q41.sql의 다음 검증 또는 설명 단계를 구성한다
- 7. W25-SQL-Q41.sql의 다음 검증 또는 설명 단계를 구성한다
- 8. SQL 집합의 입력·변환·필터 단계를 선언한다
3단계 · 파일 전체 다시 쓰기
illustrative/sql/W25-SQL-Q41.sql을 새 파일에 다시 쓰고 expected·actual·실패·cleanup·비범위를 주석으로 표시한다.
자가 점검
- 비어 있지 않은 모든 source 줄을 한 번씩 읽었나?
- 기본 트랙을 SECURITIES(증권) 하나로 두고 기본 선택·selected-track evidence·runtime Green을 서로 분리했나?
- Review·Q41·USER_ATTESTED sealed 상태를 자동 성공으로 꾸미지 않았나?
- XML bytes archive와 첫 실패·cleanup 책임을 설명할 수 있나?
STEP 13 / 13
전체 원본 source
감사로 고정한 전체 source를 가감 없이 확인합니다.
학습용 예시 전체 확인하기 · 정본 답안 아님 · NOT_RUN
-- W25-SQL-Q41 학습용 예시이며 workbook 제공 정답이 아니다.
-- 입력 grain: account 한 행은 계좌 snapshot, ledger_entry 한 행은 원장 증감 한 건이다.
-- 출력 grain: snapshot과 opening 포함 원장 합계가 다른 계좌 한 행. 현재 fixture 예상 행 수는 2다.
WITH ledger_by_account AS (
SELECT
le.account_id,
SUM(le.signed_amount) AS ledger_sum
FROM ledger_entry AS le
GROUP BY le.account_id
),
reconciled AS (
SELECT
a.account_id,
a.balance AS snapshot_balance,
COALESCE(l.ledger_sum, 0) AS ledger_sum,
a.balance - COALESCE(l.ledger_sum, 0) AS difference
FROM account AS a
LEFT JOIN ledger_by_account AS l
ON l.account_id = a.account_id
)
SELECT
account_id,
snapshot_balance,
ledger_sum,
difference
FROM reconciled
WHERE difference <> 0
ORDER BY account_id;
-- opening entry 반례: opening을 제외하면 정상 계좌도 거짓 mismatch가 된다.
-- 원장 0건 반례: LEFT JOIN과 COALESCE로 balance=0 계좌는 difference=0, 양수 snapshot은 mismatch로 남는다.
17D6 Cumulative — W25 selectorCount=1 누적 Green
illustrative/powershell/W25-D6-cumulative.ps1
학습용 예시 · W25 phase wrapper · 정본 답안 아님 · 로컬 미실행 · 학습용 예시 · 정본 답안 아님 · NOT_RUN · W25-F1737줄 연결37줄 번역4 chunks
D6 Cumulative — W25 selectorCount=1 누적 Green
illustrative/powershell/W25-D6-cumulative.ps1
학습용 예시 · W25 phase wrapper · 정본 답안 아님 · 로컬 미실행 · 학습용 예시 · 정본 답안 아님 · NOT_RUN · W25-F17STEP 01 / 13
오늘 이 코드에서 해결할 문제
무엇을 이해해야 하는지 질문부터 잡습니다.
선택 트랙의 W25..현재 selector를 누적 실행하고 첫 트랙 주차인 W25에서 exactly one suite Green과 XML archive를 확인한다.
- CumulativeGreen은 어느 source와 실제 결과에서 확인해야 할까?
- 첫 실패를 만드는 조건과 fail-closed 지점은 어디일까?
- 왜 ‘미선택 branch와 미래 주차는 누적 claim이 아니다’를 별도 경계로 남겨야 할까?
CumulativeGreenselectorCount=1tests=1status totals=0cumulative-exact.xml왜 필요한가 — D6 Cumulative — W25 selectorCount=1 누적 Green
-
CumulativeGreen가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 선택 트랙의 W25..현재 selector를 누적 실행하고 첫 트랙 주차인 W25에서 exactly one suite Green과 XML archive를 확인한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘미선택 branch와 미래 주차는 누적 claim이 아니다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 CumulativeGreen와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 02 / 13
아주 짧게: 이 코드는 왜 필요할까?
웹소설 대신 이 코드가 필요한 이유만 두 문단으로 쉽게 봅니다.
사용자의 기본 선택에 따라 이 HTML은 SECURITIES(증권)을 주 트랙으로 읽는다. CARD는 비교용이며 명시적으로 고르면 기본값을 덮어쓸 수 있다. 실제 실행은 최종 선택 한 개를 selected-track.csv·근거·state에 같은 값으로 기록하고 reference와 learner 폴더를 분리한 뒤에만 시작한다. 이 HTML 자체는 Gradle/JUnit을 실행하지 않아 NOT_RUN 상태다.
한 통장만 골라 빨강에서 초록까지 증명하는 일주일
이 파일은 선택 트랙의 W25..현재 selector를 누적 실행하고 첫 트랙 주차인 W25에서 exactly one suite Green과 XML archive를 확인한다. 눈으로 읽을 때는 각 줄을 검수표 한 칸처럼 보고, 입력과 다음 상태를 놓치지 않는다.
마지막 도장은 hash 확인, 세 test phase의 실제 JUnit 실행, XML bytes archive, 사람 review를 서로 구분한 뒤에만 찍는다. Review는 새 test가 아니며 Q41은 stage runtime 밖의 별도 NOT_RUN 과제, sealed official status는 USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED다. 특히 미선택 branch와 미래 주차는 누적 claim이 아니다
딱 여기까지만 비유와 SECURITIES 기본 배지는 실제 selected-track 근거, Gradle/JUnit 실행, XML bytes 보존, 사람 review, Q41 실행, sealed official 확인을 대신하지 않는다.
STEP 03 / 13
초등학생도 이해하는 설명
생활 비유와 실제 코드의 경계를 함께 확인합니다.
값 1: CumulativeGreen
이 파일에서 계속 확인할 고정 단서가 CumulativeGreen다.
- 코드 연결
F17 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- 미선택 branch와 미래 주차는 누적 claim이 아니다
값 2: selectorCount=1
이 파일에서 계속 확인할 고정 단서가 selectorCount=1다.
- 코드 연결
F17 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- cumulative log와 XML bytes는 별도 artifact다
값 3: tests=1
이 파일에서 계속 확인할 고정 단서가 tests=1다.
- 코드 연결
F17 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- reference와 learner root는 서로 달라야 한다
값 4: status totals=0
이 파일에서 계속 확인할 고정 단서가 status totals=0다.
- 코드 연결
F17 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
값 5: cumulative-exact.xml
이 파일에서 계속 확인할 고정 단서가 cumulative-exact.xml다.
- 코드 연결
F17 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
STEP 04 / 13
비유 ↔ 코드 전체 연결표
감사 규칙상 연결 대상인 원본 37줄을 빠짐없이 연결합니다.
| 줄 | 정확한 원본 줄 | STARRY 비유 | 실제 뜻·입력·결과·한계 |
|---|---|---|---|
| 1줄F17-L01 | # W25 PDF p38-p47의 W25부터 현재까지 누적 Green 흐름을 정리한 학습용 예시다. |
출고표 1번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다.
|
| 2줄F17-L02 | # W25는 첫 트랙 주차이므로 selectorCount= |
출고표 2번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W25 첫 트랙 주차의 누적 selector 수가 정확히 1인지 확인한다.
|
| 3줄F17-L03 | $ErrorActionPreference = |
출고표 3번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 PowerShell 오류를 계속 진행하지 않고 중단시키는 기본 정책을 둔다.
|
| 4줄F17-L04 | $ReferenceRoot = |
출고표 4번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 입력 경로를 실제 절대 경로로 확인한다.
|
| 5줄F17-L05 | $LearnerRoot = |
출고표 5번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 입력 경로를 실제 절대 경로로 확인한다.
|
| 6줄F17-L06 | if ( |
출고표 6번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 조건·반복·함수의 실행 block을 연다.
|
| 7줄F17-L07 | throw 'reference and learner roots must be different' |
출고표 7번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 8줄F17-L08 | } |
출고표 8번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 10줄F17-L10 | $Verifier = |
출고표 10번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 11줄F17-L11 | & powershell. |
출고표 11번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W25-D6-cumulative.ps1의 다음 검증 또는 설명 단계를 구성한다.
|
| 12줄F17-L12 | -ReferenceRoot $ReferenceRoot -LearnerRoot $LearnerRoot -Week 25 -Phase Cumulative -TimeoutSeconds 1200 |
출고표 12번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W25부터 현재 주까지 선택 트랙 selector를 누적 실행하는 phase다.
|
| 13줄F17-L13 | if ( |
출고표 13번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W25부터 현재 주까지 선택 트랙 selector를 누적 실행하는 phase다.
|
| 15줄F17-L15 | $State = |
출고표 15번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 JSON text를 필드로 접근 가능한 PowerShell object로 바꾼다.
|
| 16줄F17-L16 | $Entry = |
출고표 16번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 17줄F17-L17 | $Suites = |
출고표 17번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 18줄F17-L18 | if ( |
출고표 18번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W25부터 현재 주까지 선택 트랙 selector를 누적 실행하는 phase다.
|
| 19줄F17-L19 | throw 'CumulativeGreen state mismatch' |
출고표 19번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W25부터 현재 주까지 선택 트랙 selector를 누적 실행하는 phase다.
|
| 20줄F17-L20 | } |
출고표 20번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 21줄F17-L21 | if ( |
출고표 21번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W25 첫 트랙 주차의 누적 selector 수가 정확히 1인지 확인한다.
|
| 22줄F17-L22 | throw 'W25 cumulative inventory must contain exactly one Green selector' |
출고표 22번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W25부터 현재 주까지 선택 트랙 selector를 누적 실행하는 phase다.
|
| 23줄F17-L23 | } |
출고표 23번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 24줄F17-L24 | foreach ( |
출고표 24번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 고정 목록의 각 항목에 같은 검사를 반복 적용한다.
|
| 25줄F17-L25 | if ( |
출고표 25번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 조건·반복·함수의 실행 block을 연다.
|
| 26줄F17-L26 | throw "cumulative suite mismatch: |
출고표 26번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W25부터 현재 주까지 선택 트랙 selector를 누적 실행하는 phase다.
|
| 27줄F17-L27 | } |
출고표 27번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 28줄F17-L28 | } |
출고표 28번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 29줄F17-L29 | $Suite = |
출고표 29번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 30줄F17-L30 | $Xml = |
출고표 30번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 31줄F17-L31 | $ArchiveDir = |
출고표 31번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 32줄F17-L32 | New-Item -ItemType Directory -Force -Path $ArchiveDir | Out-Null |
출고표 32번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 Markdown 표 또는 PowerShell pipeline에서 값을 열이나 다음 명령으로 연결한다.
|
| 33줄F17-L33 | $Archive = |
출고표 33번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W25부터 현재 주까지 선택 트랙 selector를 누적 실행하는 phase다.
|
| 34줄F17-L34 | $Tmp = |
출고표 34번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 35줄F17-L35 | Copy-Item -LiteralPath $Xml -Destination $Tmp -Force |
출고표 35번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W25-D6-cumulative.ps1의 다음 검증 또는 설명 단계를 구성한다.
|
| 36줄F17-L36 | $ArchiveHash = |
출고표 36번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 현재 bytes를 64자리 digest로 evidence에 결박한다.
|
| 37줄F17-L37 | if ( |
출고표 37번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W25부터 현재 주까지 선택 트랙 selector를 누적 실행하는 phase다.
|
| 38줄F17-L38 | Move-Item -LiteralPath $Tmp -Destination $Archive -Force |
출고표 38번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W25-D6-cumulative.ps1의 다음 검증 또는 설명 단계를 구성한다.
|
| 39줄F17-L39 | "W25_CUMULATIVE_GREEN_VERIFIED track= |
출고표 39번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W25부터 현재 주까지 선택 트랙 selector를 누적 실행하는 phase다.
|
STEP 05 / 13
원본 코드 조각
원본을 4개 의미 조각으로 나누어 그대로 확인합니다.
파일을 한꺼번에 외우지 않고 실행 의미가 이어지는 작은 조각으로 봅니다. 아래 코드는 prompt·fixture·가정을 밝힌 학습용 예시 source이며, 제공 정본 답안이나 실행 결과가 아닌 NOT_RUN 자료입니다.
# W25 PDF p38-p47의 W25부터 현재까지 누적 Green 흐름을 정리한 학습용 예시다.
# W25는 첫 트랙 주차이므로 selectorCount=1이지만 이후 주차에는 누적 selector 수가 증가한다.
$ErrorActionPreference = 'Stop'
$ReferenceRoot = (Resolve-Path -LiteralPath $env:FINANCIAL_IT_REFERENCE_ROOT).Path
$LearnerRoot = (Resolve-Path -LiteralPath $env:FINANCIAL_IT_LEARNER_ROOT).Path
if ([string]::Equals($ReferenceRoot, $LearnerRoot, [StringComparison]::OrdinalIgnoreCase)) {
throw 'reference and learner roots must be different'
}
$Verifier = Join-Path $ReferenceRoot 'scripts\verify-track-learner-proof.ps1'
& powershell.exe -NoProfile -ExecutionPolicy Bypass -File $Verifier `
-ReferenceRoot $ReferenceRoot -LearnerRoot $LearnerRoot -Week 25 -Phase Cumulative -TimeoutSeconds 1200
if ($LASTEXITCODE -ne 0) { throw "W25 Cumulative wrapper exit=$LASTEXITCODE" }
$State = Get-Content -Raw -LiteralPath (Join-Path $LearnerRoot '.track-learning-stage.json') | ConvertFrom-Json
$Entry = @($State.history)[-1]
$Suites = @($Entry.execution.suites)
if ($State.phase -cne 'CumulativeGreen' -or $Entry.execution.mode -cne 'Cumulative') {
throw 'CumulativeGreen state mismatch'
}
if ($Entry.selectorCount -ne 1 -or $Suites.Count -ne 1 -or $Entry.execution.nativeExit -ne 0) {
throw 'W25 cumulative inventory must contain exactly one Green selector'
}
foreach ($Suite in $Suites) {
if ($Suite.tests -ne 1 -or $Suite.failures -ne 0 -or $Suite.errors -ne 0 -or $Suite.skipped -ne 0) {
throw "cumulative suite mismatch: $($Suite.class)"
}
}
$Suite = $Suites[0]
$Xml = Join-Path $LearnerRoot ("build\test-results\test\TEST-{0}.xml" -f $Suite.selector)
$ArchiveDir = Join-Path $LearnerRoot ("evidence\w25\{0}" -f $State.track.ToLowerInvariant())
New-Item -ItemType Directory -Force -Path $ArchiveDir | Out-Null
$Archive = Join-Path $ArchiveDir 'cumulative-exact.xml'
$Tmp = "$Archive.tmp"
Copy-Item -LiteralPath $Xml -Destination $Tmp -Force
$ArchiveHash = (Get-FileHash -LiteralPath $Tmp -Algorithm SHA256).Hash.ToLowerInvariant()
if ($ArchiveHash -cne $Suite.xmlSha256) { throw 'archived cumulative XML hash differs from runtime history' }
Move-Item -LiteralPath $Tmp -Destination $Archive -Force
"W25_CUMULATIVE_GREEN_VERIFIED track=$($State.track) selectors=1 tests=1 archived_xml_sha256=$ArchiveHash"
STEP 06 / 13
코드 한 줄씩 한국어로 번역
비어 있지 않은 37줄을 모두 한국어로 옮깁니다.
비어 있지 않은 원본 줄은 하나도 생략하지 않습니다.
| 줄 | 원본 | 한국어 번역 |
|---|---|---|
| 1 | # W25 PDF p38-p47의 W25부터 현재까지 누적 Green 흐름을 정리한 학습용 예시다. | 문서 의미: 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다. |
| 2 | # W25는 첫 트랙 주차이므로 selectorCount=1이지만 이후 주차에는 누적 selector 수가 증가한다. | 문서 의미: W25 첫 트랙 주차의 누적 selector 수가 정확히 1인지 확인한다. |
| 3 | $ErrorActionPreference = 'Stop' | 실행 의미: PowerShell 오류를 계속 진행하지 않고 중단시키는 기본 정책을 둔다. |
| 4 | $ReferenceRoot = (Resolve-Path -LiteralPath $env:FINANCIAL_IT_REFERENCE_ROOT).Path | 실행 의미: 입력 경로를 실제 절대 경로로 확인한다. |
| 5 | $LearnerRoot = (Resolve-Path -LiteralPath $env:FINANCIAL_IT_LEARNER_ROOT).Path | 실행 의미: 입력 경로를 실제 절대 경로로 확인한다. |
| 6 | if ([string]::Equals($ReferenceRoot, $LearnerRoot, [StringComparison]::OrdinalIgnoreCase)) { | 실행 의미: 조건·반복·함수의 실행 block을 연다. |
| 7 | throw 'reference and learner roots must be different' | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 8 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 10 | $Verifier = Join-Path $ReferenceRoot 'scripts\verify-track-learner-proof.ps1' | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 11 | & powershell.exe -NoProfile -ExecutionPolicy Bypass -File $Verifier ` | 실행 의미: W25-D6-cumulative.ps1의 다음 검증 또는 설명 단계를 구성한다. |
| 12 | -ReferenceRoot $ReferenceRoot -LearnerRoot $LearnerRoot -Week 25 -Phase Cumulative -TimeoutSeconds 1200 | 실행 의미: W25부터 현재 주까지 선택 트랙 selector를 누적 실행하는 phase다. |
| 13 | if ($LASTEXITCODE -ne 0) { throw "W25 Cumulative wrapper exit=$LASTEXITCODE" } | 실행 의미: W25부터 현재 주까지 선택 트랙 selector를 누적 실행하는 phase다. |
| 15 | $State = Get-Content -Raw -LiteralPath (Join-Path $LearnerRoot '.track-learning-stage.json') | ConvertFrom-Json | 실행 의미: JSON text를 필드로 접근 가능한 PowerShell object로 바꾼다. |
| 16 | $Entry = @($State.history)[-1] | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 17 | $Suites = @($Entry.execution.suites) | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 18 | if ($State.phase -cne 'CumulativeGreen' -or $Entry.execution.mode -cne 'Cumulative') { | 실행 의미: W25부터 현재 주까지 선택 트랙 selector를 누적 실행하는 phase다. |
| 19 | throw 'CumulativeGreen state mismatch' | 실행 의미: W25부터 현재 주까지 선택 트랙 selector를 누적 실행하는 phase다. |
| 20 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 21 | if ($Entry.selectorCount -ne 1 -or $Suites.Count -ne 1 -or $Entry.execution.nativeExit -ne 0) { | 실행 의미: W25 첫 트랙 주차의 누적 selector 수가 정확히 1인지 확인한다. |
| 22 | throw 'W25 cumulative inventory must contain exactly one Green selector' | 실행 의미: W25부터 현재 주까지 선택 트랙 selector를 누적 실행하는 phase다. |
| 23 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 24 | foreach ($Suite in $Suites) { | 실행 의미: 고정 목록의 각 항목에 같은 검사를 반복 적용한다. |
| 25 | if ($Suite.tests -ne 1 -or $Suite.failures -ne 0 -or $Suite.errors -ne 0 -or $Suite.skipped -ne 0) { | 실행 의미: 조건·반복·함수의 실행 block을 연다. |
| 26 | throw "cumulative suite mismatch: $($Suite.class)" | 실행 의미: W25부터 현재 주까지 선택 트랙 selector를 누적 실행하는 phase다. |
| 27 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 28 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 29 | $Suite = $Suites[0] | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 30 | $Xml = Join-Path $LearnerRoot ("build\test-results\test\TEST-{0}.xml" -f $Suite.selector) | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 31 | $ArchiveDir = Join-Path $LearnerRoot ("evidence\w25\{0}" -f $State.track.ToLowerInvariant()) | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 32 | New-Item -ItemType Directory -Force -Path $ArchiveDir | Out-Null | 실행 의미: Markdown 표 또는 PowerShell pipeline에서 값을 열이나 다음 명령으로 연결한다. |
| 33 | $Archive = Join-Path $ArchiveDir 'cumulative-exact.xml' | 실행 의미: W25부터 현재 주까지 선택 트랙 selector를 누적 실행하는 phase다. |
| 34 | $Tmp = "$Archive.tmp" | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 35 | Copy-Item -LiteralPath $Xml -Destination $Tmp -Force | 실행 의미: W25-D6-cumulative.ps1의 다음 검증 또는 설명 단계를 구성한다. |
| 36 | $ArchiveHash = (Get-FileHash -LiteralPath $Tmp -Algorithm SHA256).Hash.ToLowerInvariant() | 실행 의미: 현재 bytes를 64자리 digest로 evidence에 결박한다. |
| 37 | if ($ArchiveHash -cne $Suite.xmlSha256) { throw 'archived cumulative XML hash differs from runtime history' } | 실행 의미: W25부터 현재 주까지 선택 트랙 selector를 누적 실행하는 phase다. |
| 38 | Move-Item -LiteralPath $Tmp -Destination $Archive -Force | 실행 의미: W25-D6-cumulative.ps1의 다음 검증 또는 설명 단계를 구성한다. |
| 39 | "W25_CUMULATIVE_GREEN_VERIFIED track=$($State.track) selectors=1 tests=1 archived_xml_sha256=$ArchiveHash" | 실행 의미: W25부터 현재 주까지 선택 트랙 selector를 누적 실행하는 phase다. |
STEP 07 / 13
기존 수준의 한 줄 읽기·문법 해부
쉬운 설명 다음에 문법과 실행 순서를 정밀하게 읽습니다.
한 줄로 읽기D6 Cumulative — W25 selectorCount=1 누적 Green는 선택 트랙의 W25..현재 selector를 누적 실행하고 첫 트랙 주차인 W25에서 exactly one suite Green과 XML archive를 확인한다.
문법 해부
- .ps1 문법에서 선언·조건·pipeline·block 경계를 먼저 나눈다.
- manifest의 finalState와 packaged progressive test의 1_000→700/300 oracle을 서로 다른 계약으로 읽는다.
- phase state·native exit·JUnit XML hash·보존된 XML bytes·사람 판정·USER_ATTESTED external status를 서로 대체하지 않는다.
실행 순서
- 기본 트랙은 SECURITIES(증권)이며, 명시적 CARD 선택은 기본값을 덮어쓴다. 실제 실행 전 최종 선택 한 개를 selected-track.csv·근거·state에 같은 값으로 기록하고 서로 다른 reference/learner root를 확인한다.
- Prepare→VerifyStarter→RecordRed→VerifySolution→RecordGreen→Cumulative→Review 순서를 지킨다.
- test를 소유한 세 phase에서만 native exit와 exact JUnit XML 수치를 판정한다.
- 다음 cleanTest 전에 XML bytes를 고유 경로에 보존하고 runtime history hash와 다시 묶는다. Review·Q41·sealed official evidence는 각자의 별도 owner와 검증 수준으로 남긴다.
W25 조각별 정밀 해설
F17-C01 · 원문 1–12줄
- 문법 해부
- .ps1 문법으로 1–12줄의 선언·조건·phase·assert block을 나눈다.
- 실제 값 추적
- CumulativeGreen, selectorCount=1, tests=1를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- 기본 SECURITIES 또는 명시적으로 덮어쓴 CARD 중 최종 선택 한 개의 selected-track evidence와 runtime 결과에서 expected와 actual이 일치하고 owner evidence가 같은 run/hash 및 보존 XML에 연결되는 경우다. 기본/덮어쓰기 표시만 있고 실행 evidence가 없으면 NOT_RUN이다.
- 틀린 예·반례
- 미선택 branch와 미래 주차는 누적 claim이 아니다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- phase 이름·manifest finalState·history hash·exit0 하나를 W25 증거 전체와 같다고 보지 않는다.
- 하지 않는 일
- 미선택 branch와 미래 주차는 누적 claim이 아니다; cumulative log와 XML bytes는 별도 artifact다; reference와 learner root는 서로 달라야 한다; 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다; 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
- 다음 연결
- 다음 조각 또는 F17 evidence 판정으로 상태를 넘긴다.
F17-C02 · 원문 13–24줄
- 문법 해부
- .ps1 문법으로 13–24줄의 선언·조건·phase·assert block을 나눈다.
- 실제 값 추적
- CumulativeGreen, selectorCount=1, tests=1를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- 기본 SECURITIES 또는 명시적으로 덮어쓴 CARD 중 최종 선택 한 개의 selected-track evidence와 runtime 결과에서 expected와 actual이 일치하고 owner evidence가 같은 run/hash 및 보존 XML에 연결되는 경우다. 기본/덮어쓰기 표시만 있고 실행 evidence가 없으면 NOT_RUN이다.
- 틀린 예·반례
- 미선택 branch와 미래 주차는 누적 claim이 아니다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- phase 이름·manifest finalState·history hash·exit0 하나를 W25 증거 전체와 같다고 보지 않는다.
- 하지 않는 일
- 미선택 branch와 미래 주차는 누적 claim이 아니다; cumulative log와 XML bytes는 별도 artifact다; reference와 learner root는 서로 달라야 한다; 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다; 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
- 다음 연결
- 다음 조각 또는 F17 evidence 판정으로 상태를 넘긴다.
F17-C03 · 원문 25–36줄
- 문법 해부
- .ps1 문법으로 25–36줄의 선언·조건·phase·assert block을 나눈다.
- 실제 값 추적
- CumulativeGreen, selectorCount=1, tests=1를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- 기본 SECURITIES 또는 명시적으로 덮어쓴 CARD 중 최종 선택 한 개의 selected-track evidence와 runtime 결과에서 expected와 actual이 일치하고 owner evidence가 같은 run/hash 및 보존 XML에 연결되는 경우다. 기본/덮어쓰기 표시만 있고 실행 evidence가 없으면 NOT_RUN이다.
- 틀린 예·반례
- 미선택 branch와 미래 주차는 누적 claim이 아니다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- phase 이름·manifest finalState·history hash·exit0 하나를 W25 증거 전체와 같다고 보지 않는다.
- 하지 않는 일
- 미선택 branch와 미래 주차는 누적 claim이 아니다; cumulative log와 XML bytes는 별도 artifact다; reference와 learner root는 서로 달라야 한다; 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다; 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
- 다음 연결
- 다음 조각 또는 F17 evidence 판정으로 상태를 넘긴다.
F17-C04 · 원문 37–39줄
- 문법 해부
- .ps1 문법으로 37–39줄의 선언·조건·phase·assert block을 나눈다.
- 실제 값 추적
- CumulativeGreen, selectorCount=1, tests=1를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- 기본 SECURITIES 또는 명시적으로 덮어쓴 CARD 중 최종 선택 한 개의 selected-track evidence와 runtime 결과에서 expected와 actual이 일치하고 owner evidence가 같은 run/hash 및 보존 XML에 연결되는 경우다. 기본/덮어쓰기 표시만 있고 실행 evidence가 없으면 NOT_RUN이다.
- 틀린 예·반례
- 미선택 branch와 미래 주차는 누적 claim이 아니다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- phase 이름·manifest finalState·history hash·exit0 하나를 W25 증거 전체와 같다고 보지 않는다.
- 하지 않는 일
- 미선택 branch와 미래 주차는 누적 claim이 아니다; cumulative log와 XML bytes는 별도 artifact다; reference와 learner root는 서로 달라야 한다; 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다; 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
- 다음 연결
- 다음 조각 또는 F17 evidence 판정으로 상태를 넘긴다.
실행 순서 — D6 Cumulative — W25 selectorCount=1 누적 Green
-
selectorCount=1가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 선택 트랙의 W25..현재 selector를 누적 실행하고 첫 트랙 주차인 W25에서 exactly one suite Green과 XML archive를 확인한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘cumulative log와 XML bytes는 별도 artifact다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 selectorCount=1와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 08 / 13
실제 값 따라가기
같은 입력값이 어느 줄을 지나 어떤 결과가 되는지 추적합니다.
| 순서 | 들어온 값 | 코드가 하는 일 | 나온 값·상태 | 경계 |
|---|---|---|---|---|
| 입력 | CumulativeGreen | source 계약에 대입 | F17 실행/설명 시작 상태 | 미선택 branch와 미래 주차는 누적 claim이 아니다 |
| 검증 | selectorCount=1 | expected와 actual 또는 형식 대조 | 통과 또는 첫 mismatch | cumulative log와 XML bytes는 별도 artifact다 |
| 증거 | cumulative-exact.xml | marker·hash·row를 같은 run에 연결 | 범위가 적힌 evidence 후보 | 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다 |
실제 값 — D6 Cumulative — W25 selectorCount=1 누적 Green
-
tests=1가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 선택 트랙의 W25..현재 selector를 누적 실행하고 첫 트랙 주차인 W25에서 exactly one suite Green과 XML archive를 확인한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘reference와 learner root는 서로 달라야 한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 tests=1와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 09 / 13
Gradle·JUnit XML·PowerShell·SQL 내부에서 벌어지는 일
세 test phase, XML bytes archive, Review, 별도 Q41, USER_ATTESTED sealed 결과의 owner와 증명 범위를 구분합니다.
W25-D6-cumulative.ps1 bytes와 track·phase·hash 계약을 읽는다.
SECURITIES 기본 선택과 파일 존재·phase 이름만으로 runtime Green을 주장할 수 없다. 실제 selected-track evidence와 실행 결과는 별도다.RecordRed·RecordGreen·Cumulative에서만 native exit와 exact JUnit XML을 만든다.
미선택 branch와 미래 주차는 누적 claim이 아니다XML bytes를 고유 파일로 보존하고 history hash와 묶은 뒤, Review는 기존 CumulativeGreen만 인용한다. Q41은 별도 PostgreSQL evidence, sealed official status는 user-attested evidence로 남긴다.
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다첫 실패 경계 — D6 Cumulative — W25 selectorCount=1 누적 Green
-
status totals=0가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 선택 트랙의 W25..현재 selector를 누적 실행하고 첫 트랙 주차인 W25에서 exactly one suite Green과 XML archive를 확인한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 status totals=0와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 10 / 13
흔한 착각과 틀린 예
그럴듯하지만 틀린 해석을 반례로 고칩니다.
❌ Prepare·VerifyStarter·VerifySolution·Review도 Gradle을 실행해 Green을 만든다.
왜 틀리나 runtime에서 test 실행을 소유하는 phase는 RecordRed·RecordGreen·Cumulative뿐이다.
바르게 읽기 각 phase history의 execution 유무와 mode를 직접 확인한다.
반례 VerifySolution은 solution hash만 검증하므로 새 JUnit XML이 없어야 정상이다.
❌ 기본 트랙이 SECURITIES이므로 CARD도 함께 실행해도 되고, 기본 배지만으로 runtime 선택·실행 증거가 완성된다.
왜 틀리나 W25 계약은 실제 사용자 근거가 있는 선택 트랙 하나와 반대 트랙 leak 부재를 요구한다.
바르게 읽기 기본 선택은 SECURITIES(증권)이며 명시적 CARD 선택은 덮어쓰기다. 실행 전 최종 선택 한 개를 selected-track.csv·근거·state에 같은 값으로 고정한다.
반례 SECURITIES 기본 배지만 보고 test 실행을 주장하거나 두 트랙 test가 함께 보이면 선택 경계를 위반한다.
❌ progressive_contract Green이면 manifest의 finalState 10_000도 증명된다.
왜 틀리나 packaged test는 1_000에서 300을 처리한 700/300만 assert한다.
바르게 읽기 10_000 finalState는 별도 learner test 또는 사람이 결박한 evidence로 증명한다.
반례 runtime은 domainContract.finalState 문자열을 parse하거나 assert하지 않는다.
❌ history에 XML SHA가 있으니 Red·Green·Cumulative XML 원본이 모두 보존됐다.
왜 틀리나 다음 cleanTest가 build/test-results의 이전 XML을 덮어쓰며 state는 bytes를 복사하지 않는다.
바르게 읽기 각 phase 직후 고유 evidence 경로로 원자 복사하고 hash를 history와 대조한다.
반례 RecordGreen 뒤에는 Red XML 경로가 사라질 수 있다.
❌ Review가 새 test를 실행해 CumulativeGreen을 다시 만들고 Q41·sealed official 결과까지 자동 확인한다.
왜 틀리나 Review는 기존 CumulativeGreen을 전제로 review entry와 leak check만 기록한다. Q41은 별도 PostgreSQL 과제이고 sealed official status는 user-attested다.
바르게 읽기 Review에서는 reviewedPhase와 history 증가만 보고, Q41 native evidence와 USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED sealed evidence를 별도로 판정한다.
반례 Review 뒤 phase는 여전히 CumulativeGreen이고 새 execution/XML·Q41 transcript·official login verification이 생기지 않는다.
STEP 11 / 13
이 코드가 보장하지 않는 것
선택 미결정·10_000 finalState·XML 보존·Review/Q41/sealed official truth처럼 이 코드가 책임지지 않는 일을 분리합니다.
미선택 branch와 미래 주차는 누적 claim이 아니다
이 책임을 맡는 곳: runtime Gatecumulative log와 XML bytes는 별도 artifact다
이 책임을 맡는 곳: external/human reviewreference와 learner root는 서로 달라야 한다
이 책임을 맡는 곳: release manifest기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
이 책임을 맡는 곳: 운영 환경증명하지 않는 범위 — D6 Cumulative — W25 selectorCount=1 누적 Green
-
cumulative-exact.xml가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 선택 트랙의 W25..현재 selector를 누적 실행하고 첫 트랙 주차인 W25에서 exactly one suite Green과 XML archive를 확인한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 cumulative-exact.xml와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 12 / 13
직접 다시 써보기
뜻 → 조각 → 전체 코드 순서로 다시 씁니다.
1단계 · 뜻부터 복원
- 선택 트랙의 W25..현재 selector를 누적 실행하고 첫 트랙 주차인 W25에서 exactly one suite Green과 XML archive를 확인한다.
- 핵심 값은 CumulativeGreen, selectorCount=1, tests=1, status totals=0, cumulative-exact.xml다.
2단계 · 코드 조각 재조립
- 1. 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다
- 2. W25 첫 트랙 주차의 누적 selector 수가 정확히 1인지 확인한다
- 3. PowerShell 오류를 계속 진행하지 않고 중단시키는 기본 정책을 둔다
- 4. 입력 경로를 실제 절대 경로로 확인한다
- 5. 입력 경로를 실제 절대 경로로 확인한다
- 6. 조건·반복·함수의 실행 block을 연다
- 7. 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다
- 8. 앞에서 연 block 또는 호출 범위를 닫는다
3단계 · 파일 전체 다시 쓰기
illustrative/powershell/W25-D6-cumulative.ps1을 새 파일에 다시 쓰고 expected·actual·실패·cleanup·비범위를 주석으로 표시한다.
자가 점검
- 비어 있지 않은 모든 source 줄을 한 번씩 읽었나?
- 기본 트랙을 SECURITIES(증권) 하나로 두고 기본 선택·selected-track evidence·runtime Green을 서로 분리했나?
- Review·Q41·USER_ATTESTED sealed 상태를 자동 성공으로 꾸미지 않았나?
- XML bytes archive와 첫 실패·cleanup 책임을 설명할 수 있나?
STEP 13 / 13
전체 원본 source
감사로 고정한 전체 source를 가감 없이 확인합니다.
학습용 예시 전체 확인하기 · 정본 답안 아님 · NOT_RUN
# W25 PDF p38-p47의 W25부터 현재까지 누적 Green 흐름을 정리한 학습용 예시다.
# W25는 첫 트랙 주차이므로 selectorCount=1이지만 이후 주차에는 누적 selector 수가 증가한다.
$ErrorActionPreference = 'Stop'
$ReferenceRoot = (Resolve-Path -LiteralPath $env:FINANCIAL_IT_REFERENCE_ROOT).Path
$LearnerRoot = (Resolve-Path -LiteralPath $env:FINANCIAL_IT_LEARNER_ROOT).Path
if ([string]::Equals($ReferenceRoot, $LearnerRoot, [StringComparison]::OrdinalIgnoreCase)) {
throw 'reference and learner roots must be different'
}
$Verifier = Join-Path $ReferenceRoot 'scripts\verify-track-learner-proof.ps1'
& powershell.exe -NoProfile -ExecutionPolicy Bypass -File $Verifier `
-ReferenceRoot $ReferenceRoot -LearnerRoot $LearnerRoot -Week 25 -Phase Cumulative -TimeoutSeconds 1200
if ($LASTEXITCODE -ne 0) { throw "W25 Cumulative wrapper exit=$LASTEXITCODE" }
$State = Get-Content -Raw -LiteralPath (Join-Path $LearnerRoot '.track-learning-stage.json') | ConvertFrom-Json
$Entry = @($State.history)[-1]
$Suites = @($Entry.execution.suites)
if ($State.phase -cne 'CumulativeGreen' -or $Entry.execution.mode -cne 'Cumulative') {
throw 'CumulativeGreen state mismatch'
}
if ($Entry.selectorCount -ne 1 -or $Suites.Count -ne 1 -or $Entry.execution.nativeExit -ne 0) {
throw 'W25 cumulative inventory must contain exactly one Green selector'
}
foreach ($Suite in $Suites) {
if ($Suite.tests -ne 1 -or $Suite.failures -ne 0 -or $Suite.errors -ne 0 -or $Suite.skipped -ne 0) {
throw "cumulative suite mismatch: $($Suite.class)"
}
}
$Suite = $Suites[0]
$Xml = Join-Path $LearnerRoot ("build\test-results\test\TEST-{0}.xml" -f $Suite.selector)
$ArchiveDir = Join-Path $LearnerRoot ("evidence\w25\{0}" -f $State.track.ToLowerInvariant())
New-Item -ItemType Directory -Force -Path $ArchiveDir | Out-Null
$Archive = Join-Path $ArchiveDir 'cumulative-exact.xml'
$Tmp = "$Archive.tmp"
Copy-Item -LiteralPath $Xml -Destination $Tmp -Force
$ArchiveHash = (Get-FileHash -LiteralPath $Tmp -Algorithm SHA256).Hash.ToLowerInvariant()
if ($ArchiveHash -cne $Suite.xmlSha256) { throw 'archived cumulative XML hash differs from runtime history' }
Move-Item -LiteralPath $Tmp -Destination $Archive -Force
"W25_CUMULATIVE_GREEN_VERIFIED track=$($State.track) selectors=1 tests=1 archived_xml_sha256=$ArchiveHash"
18W25-S1 sealed first pass — 알고리즘 3 + SQL 1
illustrative/powershell/W25-D6-sealed-first-pass.ps1
학습용 예시 · W25 phase wrapper · 정본 답안 아님 · 로컬 미실행 · 학습용 예시 · 정본 답안 아님 · NOT_RUN · W25-F18105줄 연결105줄 번역9 chunks
W25-S1 sealed first pass — 알고리즘 3 + SQL 1
illustrative/powershell/W25-D6-sealed-first-pass.ps1
학습용 예시 · W25 phase wrapper · 정본 답안 아님 · 로컬 미실행 · 학습용 예시 · 정본 답안 아님 · NOT_RUN · W25-F18STEP 01 / 13
오늘 이 코드에서 해결할 문제
무엇을 이해해야 하는지 질문부터 잡습니다.
풀이 전 prompt를 봉인하고 exactly four rows·3 algorithm+1 SQL·shared 150m·10/16/19-field evidence 계약과 user-attested official 경계를 검증한다.
- W25-S1은 어느 source와 실제 결과에서 확인해야 할까?
- 첫 실패를 만드는 조건과 fail-closed 지점은 어디일까?
- 왜 ‘local validator는 official site에 로그인하지 않는다’를 별도 경계로 남겨야 할까?
W25-S13 algorithm + 1 SQLshared ≤150mfirst 16 fieldsretrieval 19 fields왜 필요한가 — W25-S1 sealed first pass — 알고리즘 3 + SQL 1
-
W25-S1가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 풀이 전 prompt를 봉인하고 exactly four rows·3 algorithm+1 SQL·shared 150m·10/16/19-field evidence 계약과 user-attested official 경계를 검증한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘local validator는 official site에 로그인하지 않는다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 W25-S1와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 02 / 13
아주 짧게: 이 코드는 왜 필요할까?
웹소설 대신 이 코드가 필요한 이유만 두 문단으로 쉽게 봅니다.
사용자의 기본 선택에 따라 이 HTML은 SECURITIES(증권)을 주 트랙으로 읽는다. CARD는 비교용이며 명시적으로 고르면 기본값을 덮어쓸 수 있다. 실제 실행은 최종 선택 한 개를 selected-track.csv·근거·state에 같은 값으로 기록하고 reference와 learner 폴더를 분리한 뒤에만 시작한다. 이 HTML 자체는 Gradle/JUnit을 실행하지 않아 NOT_RUN 상태다.
한 통장만 골라 빨강에서 초록까지 증명하는 일주일
이 파일은 풀이 전 prompt를 봉인하고 exactly four rows·3 algorithm+1 SQL·shared 150m·10/16/19-field evidence 계약과 user-attested official 경계를 검증한다. 눈으로 읽을 때는 각 줄을 검수표 한 칸처럼 보고, 입력과 다음 상태를 놓치지 않는다.
마지막 도장은 hash 확인, 세 test phase의 실제 JUnit 실행, XML bytes archive, 사람 review를 서로 구분한 뒤에만 찍는다. Review는 새 test가 아니며 Q41은 stage runtime 밖의 별도 NOT_RUN 과제, sealed official status는 USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED다. 특히 local validator는 official site에 로그인하지 않는다
딱 여기까지만 비유와 SECURITIES 기본 배지는 실제 selected-track 근거, Gradle/JUnit 실행, XML bytes 보존, 사람 review, Q41 실행, sealed official 확인을 대신하지 않는다.
STEP 03 / 13
초등학생도 이해하는 설명
생활 비유와 실제 코드의 경계를 함께 확인합니다.
값 1: W25-S1
이 파일에서 계속 확인할 고정 단서가 W25-S1다.
- 코드 연결
F18 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- local validator는 official site에 로그인하지 않는다
값 2: 3 algorithm + 1 SQL
이 파일에서 계속 확인할 고정 단서가 3 algorithm + 1 SQL다.
- 코드 연결
F18 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- ACCEPTED/REJECTED는 USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED다
값 3: shared ≤150m
이 파일에서 계속 확인할 고정 단서가 shared ≤150m다.
- 코드 연결
F18 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- evaluator independence를 완전 증명하지 않는다
값 4: first 16 fields
이 파일에서 계속 확인할 고정 단서가 first 16 fields다.
- 코드 연결
F18 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- reference와 learner root는 서로 달라야 한다
값 5: retrieval 19 fields
이 파일에서 계속 확인할 고정 단서가 retrieval 19 fields다.
- 코드 연결
F18 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
STEP 04 / 13
비유 ↔ 코드 전체 연결표
감사 규칙상 연결 대상인 원본 105줄을 빠짐없이 연결합니다.
| 줄 | 정확한 원본 줄 | STARRY 비유 | 실제 뜻·입력·결과·한계 |
|---|---|---|---|
| 1줄F18-L01 | $ErrorActionPreference= |
출고표 1번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 PowerShell 오류를 계속 진행하지 않고 중단시키는 기본 정책을 둔다.
|
| 2줄F18-L02 | function Read-ExactSealedKv( |
출고표 2번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 조건·반복·함수의 실행 block을 연다.
|
| 3줄F18-L03 | if( |
출고표 3번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 필수 파일이나 경로가 실제로 있는지 확인한다.
|
| 4줄F18-L04 | $raw= |
출고표 4번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 5줄F18-L05 | $map= |
출고표 5번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 6줄F18-L06 | if( |
출고표 6번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 7줄F18-L07 | return $map |
출고표 7번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W25-D6-sealed-first-pass.ps1의 다음 검증 또는 설명 단계를 구성한다.
|
| 8줄F18-L08 | } |
출고표 8번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 9줄F18-L09 | function Assert-SealedPromptContract( |
출고표 9번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 조건·반복·함수의 실행 block을 연다.
|
| 10줄F18-L10 | $required= |
출고표 10번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 11줄F18-L11 | if( |
출고표 11번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 12줄F18-L12 | if( |
출고표 12번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 13줄F18-L13 | $actual= |
출고표 13번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 현재 bytes를 64자리 digest로 evidence에 결박한다.
|
| 14줄F18-L14 | } |
출고표 14번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 15줄F18-L15 | function Assert-SealedFirstEvidence( |
출고표 15번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 조건·반복·함수의 실행 block을 연다.
|
| 16줄F18-L16 | $required= |
출고표 16번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 현재 bytes를 64자리 digest로 evidence에 결박한다.
|
| 17줄F18-L17 | if( |
출고표 17번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 18줄F18-L18 | $expectedStatus= |
출고표 18번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 각 demo 단계가 반드시 반환해야 할 HTTP status를 입력으로 고정한다.
|
| 19줄F18-L19 | $officialUri= |
출고표 19번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 20줄F18-L20 | $nativeTranscript= |
출고표 20번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 현재 bytes를 64자리 digest로 evidence에 결박한다.
|
| 21줄F18-L21 | $paths= |
출고표 21번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 22줄F18-L22 | $nativeBody= |
출고표 22번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 23줄F18-L23 | $officialBody= |
출고표 23번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 각 demo 단계가 반드시 반환해야 할 HTTP status를 입력으로 고정한다.
|
| 24줄F18-L24 | } |
출고표 24번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 25줄F18-L25 | function Assert-SealedRetrievalEvidence( |
출고표 25번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 조건·반복·함수의 실행 block을 연다.
|
| 26줄F18-L26 | $required= |
출고표 26번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 현재 bytes를 64자리 digest로 evidence에 결박한다.
|
| 27줄F18-L27 | if( |
출고표 27번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 28줄F18-L28 | if( |
출고표 28번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 현재 bytes를 64자리 digest로 evidence에 결박한다.
|
| 29줄F18-L29 | if( |
출고표 29번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 30줄F18-L30 | $expectedStatus= |
출고표 30번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 각 demo 단계가 반드시 반환해야 할 HTTP status를 입력으로 고정한다.
|
| 31줄F18-L31 | $officialUri= |
출고표 31번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 32줄F18-L32 | $nativeTranscript= |
출고표 32번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 현재 bytes를 64자리 digest로 evidence에 결박한다.
|
| 33줄F18-L33 | $paths= |
출고표 33번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 34줄F18-L34 | $nativeBody= |
출고표 34번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 35줄F18-L35 | $submissionBody= |
출고표 35번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 각 demo 단계가 반드시 반환해야 할 HTTP status를 입력으로 고정한다.
|
| 36줄F18-L36 | $actualManifest= |
출고표 36번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 현재 bytes를 64자리 digest로 evidence에 결박한다.
|
| 37줄F18-L37 | } |
출고표 37번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 38줄F18-L38 | $p= |
출고표 38번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 39줄F18-L39 | $exposurePath= |
출고표 39번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 40줄F18-L40 | foreach( |
출고표 40번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 필수 파일이나 경로가 실제로 있는지 확인한다.
|
| 41줄F18-L41 | $header= |
출고표 41번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 현재 bytes를 64자리 digest로 evidence에 결박한다.
|
| 42줄F18-L42 | if( |
출고표 42번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 43줄F18-L43 | $exposureHeader= |
출고표 43번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 44줄F18-L44 | $expectedHistoryWeeks= |
출고표 44번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 45줄F18-L45 | $historyRows= |
출고표 45번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 46줄F18-L46 | foreach( |
출고표 46번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 고정 목록의 각 항목에 같은 검사를 반복 적용한다.
|
| 47줄F18-L47 | $historyPath= |
출고표 47번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 48줄F18-L48 | if( |
출고표 48번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 필수 파일이나 경로가 실제로 있는지 확인한다.
|
| 49줄F18-L49 | $expectedHistoryHeader= |
출고표 49번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 현재 bytes를 64자리 digest로 evidence에 결박한다.
|
| 50줄F18-L50 | if( |
출고표 50번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 51줄F18-L51 | $priorRows= |
출고표 51번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 52줄F18-L52 | if( |
출고표 52번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 53줄F18-L53 | if( |
출고표 53번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 54줄F18-L54 | foreach( |
출고표 54번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 고정 목록의 각 항목에 같은 검사를 반복 적용한다.
|
| 55줄F18-L55 | foreach( |
출고표 55번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 현재 bytes를 64자리 digest로 evidence에 결박한다.
|
| 56줄F18-L56 | $historyUri= |
출고표 56번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 57줄F18-L57 | if( |
출고표 57번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 58줄F18-L58 | foreach( |
출고표 58번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 현재 bytes를 64자리 digest로 evidence에 결박한다.
|
| 59줄F18-L59 | $null= |
출고표 59번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 60줄F18-L60 | } |
출고표 60번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 61줄F18-L61 | $historyRows+ |
출고표 61번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 62줄F18-L62 | } |
출고표 62번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 63줄F18-L63 | if( |
출고표 63번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 64줄F18-L64 | $historyIds= |
출고표 64번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 고정 목록의 각 항목에 같은 검사를 반복 적용한다.
|
| 65줄F18-L65 | $allRows= |
출고표 65번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 66줄F18-L66 | $canonicalCurrentMocks= |
출고표 66번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 같은 시작 시각으로 봉인한 알고리즘 3문제와 SQL 1문제의 first pass를 가리키며 official status는 사용자 attestation 범위다.
|
| 67줄F18-L67 | if( |
출고표 67번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 68줄F18-L68 | if( |
출고표 68번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 69줄F18-L69 | foreach( |
출고표 69번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 70줄F18-L70 | $rows= |
출고표 70번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 같은 시작 시각으로 봉인한 알고리즘 3문제와 SQL 1문제의 first pass를 가리키며 official status는 사용자 attestation 범위다.
|
| 71줄F18-L71 | $exposures= |
출고표 71번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 72줄F18-L72 | if( |
출고표 72번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 73줄F18-L73 | if( |
출고표 73번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 74줄F18-L74 | if( |
출고표 74번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 75줄F18-L75 | foreach( |
출고표 75번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 필수 파일이나 경로가 실제로 있는지 확인한다.
|
| 76줄F18-L76 | $denied= |
출고표 76번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 77줄F18-L77 | $expectedMocks= |
출고표 77번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 같은 시작 시각으로 봉인한 알고리즘 3문제와 SQL 1문제의 first pass를 가리키며 official status는 사용자 attestation 범위다.
|
| 78줄F18-L78 | $requireRetrieval= |
출고표 78번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 79줄F18-L79 | foreach( |
출고표 79번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 고정 목록의 각 항목에 같은 검사를 반복 적용한다.
|
| 80줄F18-L80 | foreach( |
출고표 80번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 현재 bytes를 64자리 digest로 evidence에 결박한다.
|
| 81줄F18-L81 | if( |
출고표 81번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 82줄F18-L82 | if( |
출고표 82번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 83줄F18-L83 | if( |
출고표 83번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 84줄F18-L84 | if( |
출고표 84번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 85줄F18-L85 | if( |
출고표 85번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 86줄F18-L86 | $uri= |
출고표 86번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 87줄F18-L87 | if( |
출고표 87번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 88줄F18-L88 | if( |
출고표 88번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 89줄F18-L89 | if( |
출고표 89번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 90줄F18-L90 | foreach( |
출고표 90번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 91줄F18-L91 | $checked= |
출고표 91번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 92줄F18-L92 | if( |
출고표 92번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 93줄F18-L93 | if( |
출고표 93번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 94줄F18-L94 | if( |
출고표 94번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 95줄F18-L95 | if( |
출고표 95번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 96줄F18-L96 | if( |
출고표 96번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 97줄F18-L97 | foreach( |
출고표 97번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 현재 bytes를 64자리 digest로 evidence에 결박한다.
|
| 98줄F18-L98 | $null= |
출고표 98번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 99줄F18-L99 | if( |
출고표 99번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 현재 bytes를 64자리 digest로 evidence에 결박한다.
|
| 100줄F18-L100 | $retrievalTuple= |
출고표 100번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 현재 bytes를 64자리 digest로 evidence에 결박한다.
|
| 101줄F18-L101 | if( |
출고표 101번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 현재 bytes를 64자리 digest로 evidence에 결박한다.
|
| 102줄F18-L102 | } |
출고표 102번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 103줄F18-L103 | } |
출고표 103번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 104줄F18-L104 | foreach( |
출고표 104번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 105줄F18-L105 | if( |
출고표 105번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W25-D6-sealed-first-pass.ps1의 다음 검증 또는 설명 단계를 구성한다.
|
STEP 05 / 13
원본 코드 조각
원본을 9개 의미 조각으로 나누어 그대로 확인합니다.
파일을 한꺼번에 외우지 않고 실행 의미가 이어지는 작은 조각으로 봅니다. 아래 코드는 prompt·fixture·가정을 밝힌 학습용 예시 source이며, 제공 정본 답안이나 실행 결과가 아닌 NOT_RUN 자료입니다.
$ErrorActionPreference='Stop'
function Read-ExactSealedKv([string]$Path,[string]$Label,[string[]]$Required){
if(!(Test-Path -LiteralPath $Path -PathType Leaf) -or (Get-Item -LiteralPath $Path).Length -eq 0){throw "missing/empty ${Label}: $Path"}
$raw=Get-Content -Raw -Encoding utf8 -LiteralPath $Path;if($raw -match '(?i)\b(T[O]DO|T[B]D|PLACEHOLDER|UNCONFIRMED)\b|<[^>]+>|__[^_]+__'){throw "placeholder remains in ${Label}: $Path"}
$map=@{};foreach($line in @(Get-Content -Encoding utf8 -LiteralPath $Path)){if([string]::IsNullOrWhiteSpace($line)){continue};if($line -cnotmatch '^([A-Z][A-Z0-9_]*)=(.+)$'){throw "$Label requires exact KEY=value lines: $line"};$key=$Matches[1];$value=$Matches[2].Trim();if($map.ContainsKey($key)){throw "duplicate $Label key=$key"};if([string]::IsNullOrWhiteSpace($value)){throw "blank $Label key=$key"};$map[$key]=$value}
if($map.Count -ne $Required.Count){throw "$Label field count expected=$($Required.Count) actual=$($map.Count)"};foreach($key in $Required){if(!$map.ContainsKey($key)){throw "missing $Label key=$key"}};foreach($key in $map.Keys){if($Required -cnotcontains $key){throw "unknown $Label key=$key"}}
return $map
}
function Assert-SealedPromptContract([object]$Row){
$required=@('PROBLEM_ID','SOURCE_URL','GOAL','INPUT','OUTPUT','SIGNATURE_OR_QUERY','CONSTRAINTS','EXAMPLES','PROMPT_ONLY','SOLUTION_INCLUDED');$prompt=Read-ExactSealedKv ([string]$Row.source_evidence) 'prompt contract' $required
if($prompt.PROBLEM_ID -cne $Row.problem_id){throw "prompt problem mismatch expected=$($Row.problem_id) actual=$($prompt.PROBLEM_ID)"};if($prompt.SOURCE_URL -cne $Row.source_url){throw "prompt source URL mismatch problem=$($Row.problem_id)"}
if($prompt.PROMPT_ONLY -cne 'true' -or $prompt.SOLUTION_INCLUDED -cne 'false'){throw "prompt-only flags invalid problem=$($Row.problem_id)"}
$actual=(Get-FileHash -Algorithm SHA256 -LiteralPath $Row.source_evidence).Hash.ToLowerInvariant();if($Row.source_sha256 -cnotmatch '^[0-9a-fA-F]{64}$' -or $actual -cne $Row.source_sha256.ToLowerInvariant()){throw "prompt contract hash mismatch problem=$($Row.problem_id)"}
}
function Assert-SealedFirstEvidence([object]$Row){
$required=@('PROBLEM_ID','ATTEMPT','NATIVE_EXIT','NATIVE_COMMAND','NATIVE_TRANSCRIPT','NATIVE_TRANSCRIPT_SHA256','SOLUTION_ARTIFACT','SOLUTION_SHA256','OFFICIAL_SUBMISSION_SNAPSHOT','OFFICIAL_SUBMISSION_SHA256','OFFICIAL_SUBMISSION_URL','OFFICIAL_SUBMISSION_ID','OFFICIAL_STATUS','OFFICIAL_ATTESTATION','VERIFICATION_LEVEL','WITHOUT_MATERIALS');$manifest=Read-ExactSealedKv ([string]$Row.evidence) 'first-attempt manifest' $required
if($manifest.PROBLEM_ID -cne $Row.problem_id -or $manifest.ATTEMPT -cne 'FIRST' -or $manifest.NATIVE_EXIT -cne '0' -or $manifest.WITHOUT_MATERIALS -cne 'true'){throw "first-attempt identity/native contract mismatch problem=$($Row.problem_id)"}
$expectedStatus=if($Row.first_result -ceq 'PASS'){'ACCEPTED'}else{'REJECTED'};$expectedAttestation=if($Row.first_result -ceq 'PASS'){'USER_ATTESTED_OFFICIAL_ACCEPTED'}else{'USER_ATTESTED_OFFICIAL_REJECTED'};if($manifest.OFFICIAL_STATUS -cne $expectedStatus -or $manifest.OFFICIAL_ATTESTATION -cne $expectedAttestation -or $manifest.VERIFICATION_LEVEL -cne 'USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED'){throw "first-attempt official status/attestation mismatch problem=$($Row.problem_id)"}
$officialUri=$null;if(![uri]::TryCreate($manifest.OFFICIAL_SUBMISSION_URL,[UriKind]::Absolute,[ref]$officialUri) -or $officialUri.Scheme -cne 'https' -or $officialUri.DnsSafeHost -cne 'school.programmers.co.kr'){throw "first-attempt official submission URL must use approved host problem=$($Row.problem_id)"};if($manifest.OFFICIAL_SUBMISSION_ID -cnotmatch '^[A-Za-z0-9_-]{6,100}$'){throw "first-attempt official submission ID format invalid problem=$($Row.problem_id)"}
$nativeTranscript=[string]$manifest.NATIVE_TRANSCRIPT;$solution=[string]$manifest.SOLUTION_ARTIFACT;$officialSnapshot=[string]$manifest.OFFICIAL_SUBMISSION_SNAPSHOT;foreach($pair in @(@($nativeTranscript,$manifest.NATIVE_TRANSCRIPT_SHA256,'first native transcript'),@($solution,$manifest.SOLUTION_SHA256,'first solution'),@($officialSnapshot,$manifest.OFFICIAL_SUBMISSION_SHA256,'first official snapshot'))){if(!(Test-Path -LiteralPath $pair[0] -PathType Leaf) -or (Get-Item -LiteralPath $pair[0]).Length -eq 0){throw "missing/empty $($pair[2]) problem=$($Row.problem_id)"};$h=(Get-FileHash -Algorithm SHA256 -LiteralPath $pair[0]).Hash.ToLowerInvariant();if($pair[1] -cnotmatch '^[0-9a-fA-F]{64}$' -or $h -cne $pair[1].ToLowerInvariant()){throw "$($pair[2]) hash mismatch problem=$($Row.problem_id)"}}
$paths=@($Row.source_evidence,$Row.evidence,$nativeTranscript,$solution,$officialSnapshot)|ForEach-Object{[IO.Path]::GetFullPath([string]$_).ToLowerInvariant()};if(@($paths|Select-Object -Unique).Count -ne 5){throw "prompt, first manifest, native transcript, solution and official snapshot must use five distinct paths problem=$($Row.problem_id)"}
$nativeBody=Get-Content -Raw -Encoding utf8 -LiteralPath $nativeTranscript;foreach($token in @("PROBLEM_ID=$($Row.problem_id)",'ATTEMPT=FIRST',"COMMAND=$($manifest.NATIVE_COMMAND)",'EXIT=0')){if(!$nativeBody.Contains($token)){throw "first native transcript token missing problem=$($Row.problem_id) token=$token"}}
$officialBody=Get-Content -Raw -Encoding utf8 -LiteralPath $officialSnapshot;foreach($token in @("PROBLEM_ID=$($Row.problem_id)",'ATTEMPT=FIRST',"STATUS=$expectedStatus","OFFICIAL_SUBMISSION_URL=$($manifest.OFFICIAL_SUBMISSION_URL)","OFFICIAL_SUBMISSION_ID=$($manifest.OFFICIAL_SUBMISSION_ID)","OFFICIAL_ATTESTATION=$expectedAttestation",'VERIFICATION_LEVEL=USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED')){if(!$officialBody.Contains($token)){throw "first official snapshot token missing problem=$($Row.problem_id) token=$token"}}
}
function Assert-SealedRetrievalEvidence([object]$Row){
$required=@('PROBLEM_ID','ATTEMPT','PROMPT_SHA256','RETRIEVAL_AT','RESULT','NATIVE_EXIT','NATIVE_COMMAND','NATIVE_TRANSCRIPT','NATIVE_TRANSCRIPT_SHA256','SOLUTION_ARTIFACT','SOLUTION_SHA256','SUBMISSION_EVIDENCE','SUBMISSION_SHA256','OFFICIAL_SUBMISSION_URL','OFFICIAL_SUBMISSION_ID','OFFICIAL_STATUS','OFFICIAL_ATTESTATION','VERIFICATION_LEVEL','WITHOUT_MATERIALS');$manifest=Read-ExactSealedKv ([string]$Row.retrieval_evidence) 'retrieval manifest' $required
if($manifest.PROBLEM_ID -cne $Row.problem_id -or $manifest.ATTEMPT -cne 'RETRIEVAL'){throw "retrieval identity mismatch problem=$($Row.problem_id)"}
if($manifest.PROMPT_SHA256.ToLowerInvariant() -cne $Row.source_sha256.ToLowerInvariant()){throw "retrieval prompt hash mismatch problem=$($Row.problem_id)"};if($manifest.RETRIEVAL_AT -cne $Row.retrieval_at -or $manifest.RESULT -cne $Row.retrieval_result){throw "retrieval registry/manifest mismatch problem=$($Row.problem_id)"}
if($manifest.NATIVE_EXIT -cne '0' -or $manifest.WITHOUT_MATERIALS -cne 'true'){throw "retrieval must be a native, without-materials attempt problem=$($Row.problem_id)"}
$expectedStatus=if($Row.retrieval_result -ceq 'PASS'){'ACCEPTED'}else{'REJECTED'};$expectedAttestation=if($Row.retrieval_result -ceq 'PASS'){'USER_ATTESTED_OFFICIAL_ACCEPTED'}else{'USER_ATTESTED_OFFICIAL_REJECTED'};if($manifest.OFFICIAL_STATUS -cne $expectedStatus -or $manifest.OFFICIAL_ATTESTATION -cne $expectedAttestation){throw "retrieval official status/attestation mismatch problem=$($Row.problem_id)"};if($manifest.VERIFICATION_LEVEL -cne 'USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED'){throw "retrieval verification level must disclose non-automatic official verification problem=$($Row.problem_id)"}
$officialUri=$null;if(![uri]::TryCreate($manifest.OFFICIAL_SUBMISSION_URL,[UriKind]::Absolute,[ref]$officialUri) -or $officialUri.Scheme -cne 'https' -or $officialUri.DnsSafeHost -cne 'school.programmers.co.kr'){throw "official submission URL must use the approved host problem=$($Row.problem_id)"};if($manifest.OFFICIAL_SUBMISSION_ID -cnotmatch '^[A-Za-z0-9_-]{6,100}$'){throw "official submission ID format invalid problem=$($Row.problem_id)"}
$nativeTranscript=[string]$manifest.NATIVE_TRANSCRIPT;$solution=[string]$manifest.SOLUTION_ARTIFACT;$submission=[string]$manifest.SUBMISSION_EVIDENCE;foreach($pair in @(@($nativeTranscript,$manifest.NATIVE_TRANSCRIPT_SHA256,'native public-harness transcript'),@($solution,$manifest.SOLUTION_SHA256,'retrieval solution'),@($submission,$manifest.SUBMISSION_SHA256,'official submission snapshot'))){if(!(Test-Path -LiteralPath $pair[0] -PathType Leaf) -or (Get-Item -LiteralPath $pair[0]).Length -eq 0){throw "missing/empty $($pair[2]) problem=$($Row.problem_id)"};$h=(Get-FileHash -Algorithm SHA256 -LiteralPath $pair[0]).Hash.ToLowerInvariant();if($pair[1] -cnotmatch '^[0-9a-fA-F]{64}$' -or $h -cne $pair[1].ToLowerInvariant()){throw "$($pair[2]) hash mismatch problem=$($Row.problem_id)"}}
$paths=@($Row.source_evidence,$Row.evidence,$Row.retrieval_evidence,$nativeTranscript,$solution,$submission)|ForEach-Object{[IO.Path]::GetFullPath([string]$_).ToLowerInvariant()};if(@($paths|Select-Object -Unique).Count -ne 6){throw "prompt, first attempt, retrieval manifest, native transcript, solution and official snapshot must use six distinct paths problem=$($Row.problem_id)"}
$nativeBody=Get-Content -Raw -Encoding utf8 -LiteralPath $nativeTranscript;foreach($token in @("PROBLEM_ID=$($Row.problem_id)",'ATTEMPT=RETRIEVAL',"COMMAND=$($manifest.NATIVE_COMMAND)",'EXIT=0')){if(!$nativeBody.Contains($token)){throw "native retrieval transcript token missing problem=$($Row.problem_id) token=$token"}}
$submissionBody=Get-Content -Raw -Encoding utf8 -LiteralPath $submission;foreach($token in @("PROBLEM_ID=$($Row.problem_id)",'ATTEMPT=RETRIEVAL',"STATUS=$expectedStatus","OFFICIAL_SUBMISSION_URL=$($manifest.OFFICIAL_SUBMISSION_URL)","OFFICIAL_SUBMISSION_ID=$($manifest.OFFICIAL_SUBMISSION_ID)","OFFICIAL_ATTESTATION=$expectedAttestation",'VERIFICATION_LEVEL=USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED')){if(!$submissionBody.Contains($token)){throw "official retrieval snapshot token missing problem=$($Row.problem_id) token=$token"}};$statusMatches=[regex]::Matches($submissionBody,'(?m)^STATUS=([A-Z_]+)\s*$');if($statusMatches.Count -ne 1 -or $statusMatches[0].Groups[1].Value -cne $expectedStatus){throw "official retrieval snapshot must contain one exact status problem=$($Row.problem_id)"}
$actualManifest=(Get-FileHash -Algorithm SHA256 -LiteralPath $Row.retrieval_evidence).Hash.ToLowerInvariant();if($Row.retrieval_sha256 -cnotmatch '^[0-9a-fA-F]{64}$' -or $actualManifest -cne $Row.retrieval_sha256.ToLowerInvariant()){throw "retrieval manifest hash mismatch problem=$($Row.problem_id)"}
}
$p='evidence/w25/sealed-first-pass.csv'
$exposurePath='evidence/w25/pre-attempt-exposure.csv'
foreach($file in @($p,$exposurePath)){if(!(Test-Path -LiteralPath $file -PathType Leaf)){throw "BLOCKED_BY_EVALUATOR: missing registry $file"};$body=Get-Content -Raw -LiteralPath $file;if([string]::IsNullOrWhiteSpace($body)){throw "empty registry $file"};if($body -match '(?i)\b(T[O]DO|T[B]D|PLACEHOLDER)\b|<[^>]+>|__[^_]+__'){throw "placeholder registry $file"}}
$header='mock_id,problem_id,kind,source_url,source_checked_at,source_evidence,source_sha256,exposure_class,revealed_at,started_at,submitted_at,hint_level,native_exit,first_result,evidence,sha256,retrieval_at,retrieval_result,retrieval_evidence,retrieval_sha256'
if((Get-Content -LiteralPath $p -TotalCount 1) -cne $header){throw 'sealed registry exact header mismatch'}
$exposureHeader='problem_id,first_exposed_at,exposure_class,evidence';if((Get-Content -LiteralPath $exposurePath -TotalCount 1) -cne $exposureHeader){throw 'pre-attempt exposure exact header mismatch'}
$expectedHistoryWeeks=@()
$historyRows=@()
foreach($priorWeek in $expectedHistoryWeeks){
$historyPath=('evidence/w{0:D2}/sealed-first-pass.csv' -f [int]$priorWeek)
if(!(Test-Path -LiteralPath $historyPath -PathType Leaf)){throw "missing immutable sealed history week=W$priorWeek path=$historyPath"}
$expectedHistoryHeader=if([int]$priorWeek -ge 47){'mock_id,problem_id,kind,category,source_url,source_checked_at,source_evidence,source_sha256,exposure_class,revealed_at,started_at,submitted_at,hint_level,native_exit,first_result,evidence,sha256,retrieval_at,retrieval_result,retrieval_evidence,retrieval_sha256'}else{'mock_id,problem_id,kind,source_url,source_checked_at,source_evidence,source_sha256,exposure_class,revealed_at,started_at,submitted_at,hint_level,native_exit,first_result,evidence,sha256,retrieval_at,retrieval_result,retrieval_evidence,retrieval_sha256'}
if((Get-Content -LiteralPath $historyPath -TotalCount 1) -cne $expectedHistoryHeader){throw "sealed history header mismatch week=W$priorWeek"}
$priorRows=@(Import-Csv -LiteralPath $historyPath);$expectedPriorCount=if([int]$priorWeek -ge 47){10}else{4}
if($priorRows.Count -ne $expectedPriorCount){throw "sealed history row count mismatch week=W$priorWeek expected=$expectedPriorCount actual=$($priorRows.Count)"}
if($priorRows|Group-Object problem_id|Where-Object Count -ne 1){throw "duplicate problem ID inside sealed history week=W$priorWeek"}
foreach($priorRow in $priorRows){
foreach($field in @('problem_id','source_url','source_evidence','source_sha256','exposure_class','evidence','sha256')){if([string]::IsNullOrWhiteSpace([string]$priorRow.$field)){throw "blank sealed history $field week=W$priorWeek"}}
$historyUri=$null;if(![uri]::TryCreate($priorRow.source_url,[UriKind]::Absolute,[ref]$historyUri) -or $historyUri.Scheme -cne 'https' -or $historyUri.DnsSafeHost -cne 'school.programmers.co.kr' -or $historyUri.AbsolutePath -cnotmatch '^/learn/courses/[0-9]+/lessons/([0-9]+)/?$'){throw "unapproved sealed history source week=W$priorWeek problem=$($priorRow.problem_id)"};$historyLessonId=[regex]::Match($historyUri.AbsolutePath,'/lessons/([0-9]+)').Groups[1].Value;if($priorRow.problem_id -cne ('P'+$historyLessonId)){throw "sealed history problem/source mismatch week=W$priorWeek problem=$($priorRow.problem_id)"}
if($priorRow.exposure_class -cne 'sealed_first_pass'){throw "ineligible sealed history exposure class week=W$priorWeek problem=$($priorRow.problem_id)"}
foreach($pair in @(@($priorRow.source_evidence,$priorRow.source_sha256,'source'),@($priorRow.evidence,$priorRow.sha256,'first'))){if(!(Test-Path -LiteralPath $pair[0] -PathType Leaf) -or (Get-Item -LiteralPath $pair[0]).Length -eq 0){throw "missing/empty sealed history $($pair[2]) evidence week=W$priorWeek problem=$($priorRow.problem_id)"};$historyHash=(Get-FileHash -Algorithm SHA256 -LiteralPath $pair[0]).Hash.ToLowerInvariant();if($pair[1] -cnotmatch '^[0-9a-fA-F]{64}$' -or $historyHash -cne $pair[1].ToLowerInvariant()){throw "sealed history $($pair[2]) evidence hash mismatch week=W$priorWeek problem=$($priorRow.problem_id)"}}
$null=Assert-SealedPromptContract $priorRow;$null=Assert-SealedFirstEvidence $priorRow
}
$historyRows+=@($priorRows)
}
if($historyRows|Group-Object problem_id|Where-Object Count -ne 1){throw 'problem ID reused across prior sealed weeks'}
$historyIds=@($historyRows|ForEach-Object {$_.problem_id})
$allRows=@(Import-Csv -LiteralPath $p)
$canonicalCurrentMocks=@('W25-S1')
if($allRows|Where-Object {$canonicalCurrentMocks -cnotcontains $_.mock_id}){throw 'sealed current file contains unknown mock'}
if($allRows|Group-Object problem_id|Where-Object Count -ne 1){throw 'duplicate problem ID across current sealed mocks'}
foreach($currentGroup in @($allRows|Group-Object mock_id)){if($currentGroup.Count -ne 4){throw "partial current mock=$($currentGroup.Name) rows=$($currentGroup.Count) expected=4"}}
$rows=@($allRows|Where-Object {$_.mock_id -cin @('W25-S1')})
$exposures=@(Import-Csv -LiteralPath $exposurePath)
if($rows.Count -ne 4){throw "sealed registry requires exactly 4 rows; actual=$($rows.Count)"}
if($rows|Group-Object problem_id|Where-Object Count -ne 1){throw 'duplicate/pre-exposed problem ID collision'}
if($exposures|Group-Object problem_id|Where-Object Count -ne 1){throw 'duplicate pre-attempt exposure problem_id'}
foreach($x in $exposures){foreach($field in @('problem_id','first_exposed_at','exposure_class','evidence')){if([string]::IsNullOrWhiteSpace([string]$x.$field)){throw "blank exposure $field"}};if($x.first_exposed_at -cnotmatch '(?:Z|[+-][0-9]{2}:[0-9]{2})$'){throw "exposure timezone required: $($x.problem_id)"};if(@('textbook_exposed','guided_timed_re_solve','prior_attempt','public_solution') -cnotcontains $x.exposure_class){throw "unknown prior exposure class: $($x.exposure_class)"};if(!(Test-Path -LiteralPath $x.evidence -PathType Leaf) -or (Get-Item -LiteralPath $x.evidence).Length -eq 0){throw "missing/empty exposure evidence: $($x.problem_id)"}}
$denied=@('FCL-SQL-41','FCL-SQL-42','FCL-SQL-43','P12909','P12939','P12941','P12945','P12951','P12981','P131533','P151136','P1844','P42576','P42577','P42578','P42586','P42746','P42839','P42842','P42883','P42885','P43162','P43165','P59412','P87946')
$expectedMocks=@('W25-S1')
$requireRetrieval=$false;$pending=0
foreach($row in $rows){
foreach($field in @('mock_id','problem_id','kind','source_url','source_checked_at','source_evidence','source_sha256','exposure_class','revealed_at','started_at','submitted_at','hint_level','native_exit','first_result','evidence','sha256','retrieval_at','retrieval_result','retrieval_evidence','retrieval_sha256')){if([string]::IsNullOrWhiteSpace([string]$row.$field)){throw "blank $field problem=$($row.problem_id)"}}
if($expectedMocks -cnotcontains $row.mock_id){throw "unknown mock: $($row.mock_id)"}
if($denied -ccontains $row.problem_id){throw "known guided/pre-exposed problem ID collision: $($row.problem_id)"}
if($historyIds -ccontains $row.problem_id){throw "prior sealed problem ID collision: $($row.problem_id)"}
if(@($exposures|Where-Object {$_.problem_id -ceq $row.problem_id}).Count){throw "pre-attempt exposure collision: $($row.problem_id)"}
if(@('algorithm','SQL') -cnotcontains $row.kind){throw "kind must be algorithm|SQL: $($row.problem_id)"}
$uri=$null;if(![uri]::TryCreate($row.source_url,[UriKind]::Absolute,[ref]$uri) -or $uri.Scheme -cne 'https' -or $uri.DnsSafeHost -cne 'school.programmers.co.kr' -or $uri.AbsolutePath -cnotmatch '^/learn/courses/[0-9]+/lessons/([0-9]+)/?$'){throw "unapproved problem source: $($row.problem_id)"};$lessonId=[regex]::Match($uri.AbsolutePath,'/lessons/([0-9]+)').Groups[1].Value;if($row.problem_id -cne ('P'+$lessonId)){throw "problem_id/source lesson mismatch: $($row.problem_id) vs P$lessonId"}
if($row.exposure_class -cne 'sealed_first_pass'){throw "pre-exposed/ineligible item: $($row.problem_id)"}
if($row.hint_level -cne 'NONE'){throw "hinted item is not first-pass eligible: $($row.problem_id)"}
if($row.native_exit -cne '0' -or @('PASS','FAIL') -cnotcontains $row.first_result){throw "native exit/result invalid: $($row.problem_id)"}
foreach($timeField in @('source_checked_at','revealed_at','started_at','submitted_at')){if([string]$row.$timeField -cnotmatch '(?:Z|[+-][0-9]{2}:[0-9]{2})$'){throw "timezone required $timeField problem=$($row.problem_id)"}}
$checked=[datetimeoffset]::MinValue;$reveal=[datetimeoffset]::MinValue;$start=[datetimeoffset]::MinValue;$submit=[datetimeoffset]::MinValue
if(![datetimeoffset]::TryParse($row.source_checked_at,[ref]$checked)){throw "invalid source_checked_at: $($row.problem_id)"}
if(![datetimeoffset]::TryParse($row.revealed_at,[Globalization.CultureInfo]::InvariantCulture,[Globalization.DateTimeStyles]::RoundtripKind,[ref]$reveal)){throw "invalid revealed_at: $($row.problem_id)"}
if(![datetimeoffset]::TryParse($row.started_at,[Globalization.CultureInfo]::InvariantCulture,[Globalization.DateTimeStyles]::RoundtripKind,[ref]$start)){throw "invalid started_at: $($row.problem_id)"}
if(![datetimeoffset]::TryParse($row.submitted_at,[Globalization.CultureInfo]::InvariantCulture,[Globalization.DateTimeStyles]::RoundtripKind,[ref]$submit)){throw "invalid submitted_at: $($row.problem_id)"}
if($checked -ne $reveal -or $reveal -ne $start -or $submit -le $start -or ($submit-$start).TotalMinutes -gt 150){throw "source/reveal/start/submit timing invalid: $($row.problem_id)"}
foreach($pair in @(@($row.source_evidence,$row.source_sha256,'source'),@($row.evidence,$row.sha256,'first'))){if(!(Test-Path -LiteralPath $pair[0] -PathType Leaf) -or (Get-Item -LiteralPath $pair[0]).Length -eq 0){throw "missing/empty $($pair[2]) evidence: $($row.problem_id)"};$h=(Get-FileHash -Algorithm SHA256 -LiteralPath $pair[0]).Hash.ToLowerInvariant();if($pair[1] -cnotmatch '^[0-9a-fA-F]{64}$' -or $h -cne $pair[1].ToLowerInvariant()){throw "$($pair[2]) evidence hash mismatch: $($row.problem_id)"}}
$null=Assert-SealedPromptContract $row;$null=Assert-SealedFirstEvidence $row
if($row.first_result -ceq 'PASS'){if(@($row.retrieval_at,$row.retrieval_result,$row.retrieval_evidence,$row.retrieval_sha256)|Where-Object {$_ -cne 'N-A_FAST_TRACK'}){throw "PASS item must use exact N-A_FAST_TRACK retrieval tuple: $($row.problem_id)"}}else{
$retrievalTuple=@($row.retrieval_at,$row.retrieval_result,$row.retrieval_evidence,$row.retrieval_sha256);$pendingFields=@($retrievalTuple|Where-Object {$_ -ceq 'PENDING_D+2'}).Count;if($pendingFields){if($pendingFields -ne 4){throw "mixed pending retrieval tuple: $($row.problem_id)"};if($requireRetrieval){throw "D+2 retrieval still pending: $($row.problem_id)"};$pending++;continue}
if(@($retrievalTuple|Where-Object {$_ -ceq 'N-A_FAST_TRACK'}).Count){throw "FAIL item cannot fast-track retrieval: $($row.problem_id)"};if($row.retrieval_result -cnotin @('PASS','FAIL')){throw "invalid retrieval_result: $($row.problem_id)"};$retry=[datetimeoffset]::MinValue;if($row.retrieval_at -cnotmatch '(?:Z|[+-][0-9]{2}:[0-9]{2})$' -or ![datetimeoffset]::TryParse($row.retrieval_at,[ref]$retry) -or ($retry-$submit).TotalHours -lt 46 -or ($retry-$submit).TotalHours -gt 74){throw "D+2 retrieval window must be 46-74h: $($row.problem_id)"};if(!(Test-Path -LiteralPath $row.retrieval_evidence -PathType Leaf) -or (Get-Item -LiteralPath $row.retrieval_evidence).Length -eq 0){throw "missing/empty retrieval evidence: $($row.problem_id)"};$rh=(Get-FileHash -Algorithm SHA256 -LiteralPath $row.retrieval_evidence).Hash.ToLowerInvariant();if($row.retrieval_sha256 -cnotmatch '^[0-9a-fA-F]{64}$' -or $rh -cne $row.retrieval_sha256.ToLowerInvariant()){throw "retrieval evidence hash mismatch: $($row.problem_id)"};"--- RETRIEVAL CONTRACT problem=$($row.problem_id) prompt_sha256=$($row.source_sha256) ---";Get-Content -Encoding utf8 -LiteralPath $row.source_evidence;$null=Assert-SealedRetrievalEvidence $row
}
}
foreach($mock in $expectedMocks){$m=@($rows|Where-Object {$_.mock_id -ceq $mock});$alg=@($m|Where-Object {$_.kind -ceq 'algorithm'});$sql=@($m|Where-Object {$_.kind -ceq 'SQL'});if($m.Count -ne 4 -or $alg.Count -ne 3 -or $sql.Count -ne 1){throw "$mock must be exact 3 algorithm + 1 SQL"};$starts=@($m.started_at|Select-Object -Unique);$submits=@($m.submitted_at|Select-Object -Unique);if($starts.Count -ne 1 -or $submits.Count -ne 1){throw "$mock timestamps must be one shared attempt window"}}
if($pending -gt 0){'PASS_FIRST_ATTEMPT W25 mocks=1 composition=3+1 contract_scope=STRUCTURE_HASH_TIMING official_result=USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED pending_D+2='+$pending}else{'PASS_LONG_TERM W25 mocks=1 composition=3+1 contract_scope=RETRIEVAL_STRUCTURE_HASH_TIMING official_result=USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED'}
STEP 06 / 13
코드 한 줄씩 한국어로 번역
비어 있지 않은 105줄을 모두 한국어로 옮깁니다.
비어 있지 않은 원본 줄은 하나도 생략하지 않습니다.
| 줄 | 원본 | 한국어 번역 |
|---|---|---|
| 1 | $ErrorActionPreference='Stop' | 실행 의미: PowerShell 오류를 계속 진행하지 않고 중단시키는 기본 정책을 둔다. |
| 2 | function Read-ExactSealedKv([string]$Path,[string]$Label,[string[]]$Required){ | 실행 의미: 조건·반복·함수의 실행 block을 연다. |
| 3 | if(!(Test-Path -LiteralPath $Path -PathType Leaf) -or (Get-Item -LiteralPath $Path).Length -eq 0){throw "missing/empty ${Label}: $Path"} | 실행 의미: 필수 파일이나 경로가 실제로 있는지 확인한다. |
| 4 | $raw=Get-Content -Raw -Encoding utf8 -LiteralPath $Path;if($raw -match '(?i)\b(T[O]DO|T[B]D|PLACEHOLDER|UNCONFIRMED)\b|<[^>]+>|__[^_]+__'){throw "placeholder remains in ${Label}: $Path"} | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 5 | $map=@{};foreach($line in @(Get-Content -Encoding utf8 -LiteralPath $Path)){if([string]::IsNullOrWhiteSpace($line)){continue};if($line -cnotmatch '^([A-Z][A-Z0-9_]*)=(.+)$'){throw "$Label requires exact KEY=value lines: $line"};$key=$Matches[1];$value=$Matches[2].Trim();if($map.ContainsKey($key)){throw "duplicate $Label key=$key"};if([string]::IsNullOrWhiteSpace($value)){throw "blank $Label key=$key"};$map[$key]=$value} | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 6 | if($map.Count -ne $Required.Count){throw "$Label field count expected=$($Required.Count) actual=$($map.Count)"};foreach($key in $Required){if(!$map.ContainsKey($key)){throw "missing $Label key=$key"}};foreach($key in $map.Keys){if($Required -cnotcontains $key){throw "unknown $Label key=$key"}} | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 7 | return $map | 실행 의미: W25-D6-sealed-first-pass.ps1의 다음 검증 또는 설명 단계를 구성한다. |
| 8 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 9 | function Assert-SealedPromptContract([object]$Row){ | 실행 의미: 조건·반복·함수의 실행 block을 연다. |
| 10 | $required=@('PROBLEM_ID','SOURCE_URL','GOAL','INPUT','OUTPUT','SIGNATURE_OR_QUERY','CONSTRAINTS','EXAMPLES','PROMPT_ONLY','SOLUTION_INCLUDED');$prompt=Read-ExactSealedKv ([string]$Row.source_evidence) 'prompt contract' $required | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 11 | if($prompt.PROBLEM_ID -cne $Row.problem_id){throw "prompt problem mismatch expected=$($Row.problem_id) actual=$($prompt.PROBLEM_ID)"};if($prompt.SOURCE_URL -cne $Row.source_url){throw "prompt source URL mismatch problem=$($Row.problem_id)"} | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 12 | if($prompt.PROMPT_ONLY -cne 'true' -or $prompt.SOLUTION_INCLUDED -cne 'false'){throw "prompt-only flags invalid problem=$($Row.problem_id)"} | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 13 | $actual=(Get-FileHash -Algorithm SHA256 -LiteralPath $Row.source_evidence).Hash.ToLowerInvariant();if($Row.source_sha256 -cnotmatch '^[0-9a-fA-F]{64}$' -or $actual -cne $Row.source_sha256.ToLowerInvariant()){throw "prompt contract hash mismatch problem=$($Row.problem_id)"} | 실행 의미: 현재 bytes를 64자리 digest로 evidence에 결박한다. |
| 14 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 15 | function Assert-SealedFirstEvidence([object]$Row){ | 실행 의미: 조건·반복·함수의 실행 block을 연다. |
| 16 | $required=@('PROBLEM_ID','ATTEMPT','NATIVE_EXIT','NATIVE_COMMAND','NATIVE_TRANSCRIPT','NATIVE_TRANSCRIPT_SHA256','SOLUTION_ARTIFACT','SOLUTION_SHA256','OFFICIAL_SUBMISSION_SNAPSHOT','OFFICIAL_SUBMISSION_SHA256','OFFICIAL_SUBMISSION_URL','OFFICIAL_SUBMISSION_ID','OFFICIAL_STATUS','OFFICIAL_ATTESTATION','VERIFICATION_LEVEL','WITHOUT_MATERIALS');$manifest=Read-ExactSealedKv ([string]$Row.evidence) 'first-attempt manifest' $required | 실행 의미: 현재 bytes를 64자리 digest로 evidence에 결박한다. |
| 17 | if($manifest.PROBLEM_ID -cne $Row.problem_id -or $manifest.ATTEMPT -cne 'FIRST' -or $manifest.NATIVE_EXIT -cne '0' -or $manifest.WITHOUT_MATERIALS -cne 'true'){throw "first-attempt identity/native contract mismatch problem=$($Row.problem_id)"} | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 18 | $expectedStatus=if($Row.first_result -ceq 'PASS'){'ACCEPTED'}else{'REJECTED'};$expectedAttestation=if($Row.first_result -ceq 'PASS'){'USER_ATTESTED_OFFICIAL_ACCEPTED'}else{'USER_ATTESTED_OFFICIAL_REJECTED'};if($manifest.OFFICIAL_STATUS -cne $expectedStatus -or $manifest.OFFICIAL_ATTESTATION -cne $expectedAttestation -or $manifest.VERIFICATION_LEVEL -cne 'USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED'){throw "first-attempt official status/attestation mismatch problem=$($Row.problem_id)"} | 실행 의미: 각 demo 단계가 반드시 반환해야 할 HTTP status를 입력으로 고정한다. |
| 19 | $officialUri=$null;if(![uri]::TryCreate($manifest.OFFICIAL_SUBMISSION_URL,[UriKind]::Absolute,[ref]$officialUri) -or $officialUri.Scheme -cne 'https' -or $officialUri.DnsSafeHost -cne 'school.programmers.co.kr'){throw "first-attempt official submission URL must use approved host problem=$($Row.problem_id)"};if($manifest.OFFICIAL_SUBMISSION_ID -cnotmatch '^[A-Za-z0-9_-]{6,100}$'){throw "first-attempt official submission ID format invalid problem=$($Row.problem_id)"} | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 20 | $nativeTranscript=[string]$manifest.NATIVE_TRANSCRIPT;$solution=[string]$manifest.SOLUTION_ARTIFACT;$officialSnapshot=[string]$manifest.OFFICIAL_SUBMISSION_SNAPSHOT;foreach($pair in @(@($nativeTranscript,$manifest.NATIVE_TRANSCRIPT_SHA256,'first native transcript'),@($solution,$manifest.SOLUTION_SHA256,'first solution'),@($officialSnapshot,$manifest.OFFICIAL_SUBMISSION_SHA256,'first official snapshot'))){if(!(Test-Path -LiteralPath $pair[0] -PathType Leaf) -or (Get-Item -LiteralPath $pair[0]).Length -eq 0){throw "missing/empty $($pair[2]) problem=$($Row.problem_id)"};$h=(Get-FileHash -Algorithm SHA256 -LiteralPath $pair[0]).Hash.ToLowerInvariant();if($pair[1] -cnotmatch '^[0-9a-fA-F]{64}$' -or $h -cne $pair[1].ToLowerInvariant()){throw "$($pair[2]) hash mismatch problem=$($Row.problem_id)"}} | 실행 의미: 현재 bytes를 64자리 digest로 evidence에 결박한다. |
| 21 | $paths=@($Row.source_evidence,$Row.evidence,$nativeTranscript,$solution,$officialSnapshot)|ForEach-Object{[IO.Path]::GetFullPath([string]$_).ToLowerInvariant()};if(@($paths|Select-Object -Unique).Count -ne 5){throw "prompt, first manifest, native transcript, solution and official snapshot must use five distinct paths problem=$($Row.problem_id)"} | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 22 | $nativeBody=Get-Content -Raw -Encoding utf8 -LiteralPath $nativeTranscript;foreach($token in @("PROBLEM_ID=$($Row.problem_id)",'ATTEMPT=FIRST',"COMMAND=$($manifest.NATIVE_COMMAND)",'EXIT=0')){if(!$nativeBody.Contains($token)){throw "first native transcript token missing problem=$($Row.problem_id) token=$token"}} | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 23 | $officialBody=Get-Content -Raw -Encoding utf8 -LiteralPath $officialSnapshot;foreach($token in @("PROBLEM_ID=$($Row.problem_id)",'ATTEMPT=FIRST',"STATUS=$expectedStatus","OFFICIAL_SUBMISSION_URL=$($manifest.OFFICIAL_SUBMISSION_URL)","OFFICIAL_SUBMISSION_ID=$($manifest.OFFICIAL_SUBMISSION_ID)","OFFICIAL_ATTESTATION=$expectedAttestation",'VERIFICATION_LEVEL=USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED')){if(!$officialBody.Contains($token)){throw "first official snapshot token missing problem=$($Row.problem_id) token=$token"}} | 실행 의미: 각 demo 단계가 반드시 반환해야 할 HTTP status를 입력으로 고정한다. |
| 24 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 25 | function Assert-SealedRetrievalEvidence([object]$Row){ | 실행 의미: 조건·반복·함수의 실행 block을 연다. |
| 26 | $required=@('PROBLEM_ID','ATTEMPT','PROMPT_SHA256','RETRIEVAL_AT','RESULT','NATIVE_EXIT','NATIVE_COMMAND','NATIVE_TRANSCRIPT','NATIVE_TRANSCRIPT_SHA256','SOLUTION_ARTIFACT','SOLUTION_SHA256','SUBMISSION_EVIDENCE','SUBMISSION_SHA256','OFFICIAL_SUBMISSION_URL','OFFICIAL_SUBMISSION_ID','OFFICIAL_STATUS','OFFICIAL_ATTESTATION','VERIFICATION_LEVEL','WITHOUT_MATERIALS');$manifest=Read-ExactSealedKv ([string]$Row.retrieval_evidence) 'retrieval manifest' $required | 실행 의미: 현재 bytes를 64자리 digest로 evidence에 결박한다. |
| 27 | if($manifest.PROBLEM_ID -cne $Row.problem_id -or $manifest.ATTEMPT -cne 'RETRIEVAL'){throw "retrieval identity mismatch problem=$($Row.problem_id)"} | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 28 | if($manifest.PROMPT_SHA256.ToLowerInvariant() -cne $Row.source_sha256.ToLowerInvariant()){throw "retrieval prompt hash mismatch problem=$($Row.problem_id)"};if($manifest.RETRIEVAL_AT -cne $Row.retrieval_at -or $manifest.RESULT -cne $Row.retrieval_result){throw "retrieval registry/manifest mismatch problem=$($Row.problem_id)"} | 실행 의미: 현재 bytes를 64자리 digest로 evidence에 결박한다. |
| 29 | if($manifest.NATIVE_EXIT -cne '0' -or $manifest.WITHOUT_MATERIALS -cne 'true'){throw "retrieval must be a native, without-materials attempt problem=$($Row.problem_id)"} | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 30 | $expectedStatus=if($Row.retrieval_result -ceq 'PASS'){'ACCEPTED'}else{'REJECTED'};$expectedAttestation=if($Row.retrieval_result -ceq 'PASS'){'USER_ATTESTED_OFFICIAL_ACCEPTED'}else{'USER_ATTESTED_OFFICIAL_REJECTED'};if($manifest.OFFICIAL_STATUS -cne $expectedStatus -or $manifest.OFFICIAL_ATTESTATION -cne $expectedAttestation){throw "retrieval official status/attestation mismatch problem=$($Row.problem_id)"};if($manifest.VERIFICATION_LEVEL -cne 'USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED'){throw "retrieval verification level must disclose non-automatic official verification problem=$($Row.problem_id)"} | 실행 의미: 각 demo 단계가 반드시 반환해야 할 HTTP status를 입력으로 고정한다. |
| 31 | $officialUri=$null;if(![uri]::TryCreate($manifest.OFFICIAL_SUBMISSION_URL,[UriKind]::Absolute,[ref]$officialUri) -or $officialUri.Scheme -cne 'https' -or $officialUri.DnsSafeHost -cne 'school.programmers.co.kr'){throw "official submission URL must use the approved host problem=$($Row.problem_id)"};if($manifest.OFFICIAL_SUBMISSION_ID -cnotmatch '^[A-Za-z0-9_-]{6,100}$'){throw "official submission ID format invalid problem=$($Row.problem_id)"} | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 32 | $nativeTranscript=[string]$manifest.NATIVE_TRANSCRIPT;$solution=[string]$manifest.SOLUTION_ARTIFACT;$submission=[string]$manifest.SUBMISSION_EVIDENCE;foreach($pair in @(@($nativeTranscript,$manifest.NATIVE_TRANSCRIPT_SHA256,'native public-harness transcript'),@($solution,$manifest.SOLUTION_SHA256,'retrieval solution'),@($submission,$manifest.SUBMISSION_SHA256,'official submission snapshot'))){if(!(Test-Path -LiteralPath $pair[0] -PathType Leaf) -or (Get-Item -LiteralPath $pair[0]).Length -eq 0){throw "missing/empty $($pair[2]) problem=$($Row.problem_id)"};$h=(Get-FileHash -Algorithm SHA256 -LiteralPath $pair[0]).Hash.ToLowerInvariant();if($pair[1] -cnotmatch '^[0-9a-fA-F]{64}$' -or $h -cne $pair[1].ToLowerInvariant()){throw "$($pair[2]) hash mismatch problem=$($Row.problem_id)"}} | 실행 의미: 현재 bytes를 64자리 digest로 evidence에 결박한다. |
| 33 | $paths=@($Row.source_evidence,$Row.evidence,$Row.retrieval_evidence,$nativeTranscript,$solution,$submission)|ForEach-Object{[IO.Path]::GetFullPath([string]$_).ToLowerInvariant()};if(@($paths|Select-Object -Unique).Count -ne 6){throw "prompt, first attempt, retrieval manifest, native transcript, solution and official snapshot must use six distinct paths problem=$($Row.problem_id)"} | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 34 | $nativeBody=Get-Content -Raw -Encoding utf8 -LiteralPath $nativeTranscript;foreach($token in @("PROBLEM_ID=$($Row.problem_id)",'ATTEMPT=RETRIEVAL',"COMMAND=$($manifest.NATIVE_COMMAND)",'EXIT=0')){if(!$nativeBody.Contains($token)){throw "native retrieval transcript token missing problem=$($Row.problem_id) token=$token"}} | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 35 | $submissionBody=Get-Content -Raw -Encoding utf8 -LiteralPath $submission;foreach($token in @("PROBLEM_ID=$($Row.problem_id)",'ATTEMPT=RETRIEVAL',"STATUS=$expectedStatus","OFFICIAL_SUBMISSION_URL=$($manifest.OFFICIAL_SUBMISSION_URL)","OFFICIAL_SUBMISSION_ID=$($manifest.OFFICIAL_SUBMISSION_ID)","OFFICIAL_ATTESTATION=$expectedAttestation",'VERIFICATION_LEVEL=USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED')){if(!$submissionBody.Contains($token)){throw "official retrieval snapshot token missing problem=$($Row.problem_id) token=$token"}};$statusMatches=[regex]::Matches($submissionBody,'(?m)^STATUS=([A-Z_]+)\s*$');if($statusMatches.Count -ne 1 -or $statusMatches[0].Groups[1].Value -cne $expectedStatus){throw "official retrieval snapshot must contain one exact status problem=$($Row.problem_id)"} | 실행 의미: 각 demo 단계가 반드시 반환해야 할 HTTP status를 입력으로 고정한다. |
| 36 | $actualManifest=(Get-FileHash -Algorithm SHA256 -LiteralPath $Row.retrieval_evidence).Hash.ToLowerInvariant();if($Row.retrieval_sha256 -cnotmatch '^[0-9a-fA-F]{64}$' -or $actualManifest -cne $Row.retrieval_sha256.ToLowerInvariant()){throw "retrieval manifest hash mismatch problem=$($Row.problem_id)"} | 실행 의미: 현재 bytes를 64자리 digest로 evidence에 결박한다. |
| 37 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 38 | $p='evidence/w25/sealed-first-pass.csv' | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 39 | $exposurePath='evidence/w25/pre-attempt-exposure.csv' | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 40 | foreach($file in @($p,$exposurePath)){if(!(Test-Path -LiteralPath $file -PathType Leaf)){throw "BLOCKED_BY_EVALUATOR: missing registry $file"};$body=Get-Content -Raw -LiteralPath $file;if([string]::IsNullOrWhiteSpace($body)){throw "empty registry $file"};if($body -match '(?i)\b(T[O]DO|T[B]D|PLACEHOLDER)\b|<[^>]+>|__[^_]+__'){throw "placeholder registry $file"}} | 실행 의미: 필수 파일이나 경로가 실제로 있는지 확인한다. |
| 41 | $header='mock_id,problem_id,kind,source_url,source_checked_at,source_evidence,source_sha256,exposure_class,revealed_at,started_at,submitted_at,hint_level,native_exit,first_result,evidence,sha256,retrieval_at,retrieval_result,retrieval_evidence,retrieval_sha256' | 실행 의미: 현재 bytes를 64자리 digest로 evidence에 결박한다. |
| 42 | if((Get-Content -LiteralPath $p -TotalCount 1) -cne $header){throw 'sealed registry exact header mismatch'} | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 43 | $exposureHeader='problem_id,first_exposed_at,exposure_class,evidence';if((Get-Content -LiteralPath $exposurePath -TotalCount 1) -cne $exposureHeader){throw 'pre-attempt exposure exact header mismatch'} | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 44 | $expectedHistoryWeeks=@() | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 45 | $historyRows=@() | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 46 | foreach($priorWeek in $expectedHistoryWeeks){ | 실행 의미: 고정 목록의 각 항목에 같은 검사를 반복 적용한다. |
| 47 | $historyPath=('evidence/w{0:D2}/sealed-first-pass.csv' -f [int]$priorWeek) | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 48 | if(!(Test-Path -LiteralPath $historyPath -PathType Leaf)){throw "missing immutable sealed history week=W$priorWeek path=$historyPath"} | 실행 의미: 필수 파일이나 경로가 실제로 있는지 확인한다. |
| 49 | $expectedHistoryHeader=if([int]$priorWeek -ge 47){'mock_id,problem_id,kind,category,source_url,source_checked_at,source_evidence,source_sha256,exposure_class,revealed_at,started_at,submitted_at,hint_level,native_exit,first_result,evidence,sha256,retrieval_at,retrieval_result,retrieval_evidence,retrieval_sha256'}else{'mock_id,problem_id,kind,source_url,source_checked_at,source_evidence,source_sha256,exposure_class,revealed_at,started_at,submitted_at,hint_level,native_exit,first_result,evidence,sha256,retrieval_at,retrieval_result,retrieval_evidence,retrieval_sha256'} | 실행 의미: 현재 bytes를 64자리 digest로 evidence에 결박한다. |
| 50 | if((Get-Content -LiteralPath $historyPath -TotalCount 1) -cne $expectedHistoryHeader){throw "sealed history header mismatch week=W$priorWeek"} | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 51 | $priorRows=@(Import-Csv -LiteralPath $historyPath);$expectedPriorCount=if([int]$priorWeek -ge 47){10}else{4} | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 52 | if($priorRows.Count -ne $expectedPriorCount){throw "sealed history row count mismatch week=W$priorWeek expected=$expectedPriorCount actual=$($priorRows.Count)"} | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 53 | if($priorRows|Group-Object problem_id|Where-Object Count -ne 1){throw "duplicate problem ID inside sealed history week=W$priorWeek"} | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 54 | foreach($priorRow in $priorRows){ | 실행 의미: 고정 목록의 각 항목에 같은 검사를 반복 적용한다. |
| 55 | foreach($field in @('problem_id','source_url','source_evidence','source_sha256','exposure_class','evidence','sha256')){if([string]::IsNullOrWhiteSpace([string]$priorRow.$field)){throw "blank sealed history $field week=W$priorWeek"}} | 실행 의미: 현재 bytes를 64자리 digest로 evidence에 결박한다. |
| 56 | $historyUri=$null;if(![uri]::TryCreate($priorRow.source_url,[UriKind]::Absolute,[ref]$historyUri) -or $historyUri.Scheme -cne 'https' -or $historyUri.DnsSafeHost -cne 'school.programmers.co.kr' -or $historyUri.AbsolutePath -cnotmatch '^/learn/courses/[0-9]+/lessons/([0-9]+)/?$'){throw "unapproved sealed history source week=W$priorWeek problem=$($priorRow.problem_id)"};$historyLessonId=[regex]::Match($historyUri.AbsolutePath,'/lessons/([0-9]+)').Groups[1].Value;if($priorRow.problem_id -cne ('P'+$historyLessonId)){throw "sealed history problem/source mismatch week=W$priorWeek problem=$($priorRow.problem_id)"} | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 57 | if($priorRow.exposure_class -cne 'sealed_first_pass'){throw "ineligible sealed history exposure class week=W$priorWeek problem=$($priorRow.problem_id)"} | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 58 | foreach($pair in @(@($priorRow.source_evidence,$priorRow.source_sha256,'source'),@($priorRow.evidence,$priorRow.sha256,'first'))){if(!(Test-Path -LiteralPath $pair[0] -PathType Leaf) -or (Get-Item -LiteralPath $pair[0]).Length -eq 0){throw "missing/empty sealed history $($pair[2]) evidence week=W$priorWeek problem=$($priorRow.problem_id)"};$historyHash=(Get-FileHash -Algorithm SHA256 -LiteralPath $pair[0]).Hash.ToLowerInvariant();if($pair[1] -cnotmatch '^[0-9a-fA-F]{64}$' -or $historyHash -cne $pair[1].ToLowerInvariant()){throw "sealed history $($pair[2]) evidence hash mismatch week=W$priorWeek problem=$($priorRow.problem_id)"}} | 실행 의미: 현재 bytes를 64자리 digest로 evidence에 결박한다. |
| 59 | $null=Assert-SealedPromptContract $priorRow;$null=Assert-SealedFirstEvidence $priorRow | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 60 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 61 | $historyRows+=@($priorRows) | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 62 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 63 | if($historyRows|Group-Object problem_id|Where-Object Count -ne 1){throw 'problem ID reused across prior sealed weeks'} | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 64 | $historyIds=@($historyRows|ForEach-Object {$_.problem_id}) | 실행 의미: 고정 목록의 각 항목에 같은 검사를 반복 적용한다. |
| 65 | $allRows=@(Import-Csv -LiteralPath $p) | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 66 | $canonicalCurrentMocks=@('W25-S1') | 실행 의미: 같은 시작 시각으로 봉인한 알고리즘 3문제와 SQL 1문제의 first pass를 가리키며 official status는 사용자 attestation 범위다. |
| 67 | if($allRows|Where-Object {$canonicalCurrentMocks -cnotcontains $_.mock_id}){throw 'sealed current file contains unknown mock'} | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 68 | if($allRows|Group-Object problem_id|Where-Object Count -ne 1){throw 'duplicate problem ID across current sealed mocks'} | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 69 | foreach($currentGroup in @($allRows|Group-Object mock_id)){if($currentGroup.Count -ne 4){throw "partial current mock=$($currentGroup.Name) rows=$($currentGroup.Count) expected=4"}} | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 70 | $rows=@($allRows|Where-Object {$_.mock_id -cin @('W25-S1')}) | 실행 의미: 같은 시작 시각으로 봉인한 알고리즘 3문제와 SQL 1문제의 first pass를 가리키며 official status는 사용자 attestation 범위다. |
| 71 | $exposures=@(Import-Csv -LiteralPath $exposurePath) | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 72 | if($rows.Count -ne 4){throw "sealed registry requires exactly 4 rows; actual=$($rows.Count)"} | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 73 | if($rows|Group-Object problem_id|Where-Object Count -ne 1){throw 'duplicate/pre-exposed problem ID collision'} | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 74 | if($exposures|Group-Object problem_id|Where-Object Count -ne 1){throw 'duplicate pre-attempt exposure problem_id'} | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 75 | foreach($x in $exposures){foreach($field in @('problem_id','first_exposed_at','exposure_class','evidence')){if([string]::IsNullOrWhiteSpace([string]$x.$field)){throw "blank exposure $field"}};if($x.first_exposed_at -cnotmatch '(?:Z|[+-][0-9]{2}:[0-9]{2})$'){throw "exposure timezone required: $($x.problem_id)"};if(@('textbook_exposed','guided_timed_re_solve','prior_attempt','public_solution') -cnotcontains $x.exposure_class){throw "unknown prior exposure class: $($x.exposure_class)"};if(!(Test-Path -LiteralPath $x.evidence -PathType Leaf) -or (Get-Item -LiteralPath $x.evidence).Length -eq 0){throw "missing/empty exposure evidence: $($x.problem_id)"}} | 실행 의미: 필수 파일이나 경로가 실제로 있는지 확인한다. |
| 76 | $denied=@('FCL-SQL-41','FCL-SQL-42','FCL-SQL-43','P12909','P12939','P12941','P12945','P12951','P12981','P131533','P151136','P1844','P42576','P42577','P42578','P42586','P42746','P42839','P42842','P42883','P42885','P43162','P43165','P59412','P87946') | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 77 | $expectedMocks=@('W25-S1') | 실행 의미: 같은 시작 시각으로 봉인한 알고리즘 3문제와 SQL 1문제의 first pass를 가리키며 official status는 사용자 attestation 범위다. |
| 78 | $requireRetrieval=$false;$pending=0 | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 79 | foreach($row in $rows){ | 실행 의미: 고정 목록의 각 항목에 같은 검사를 반복 적용한다. |
| 80 | foreach($field in @('mock_id','problem_id','kind','source_url','source_checked_at','source_evidence','source_sha256','exposure_class','revealed_at','started_at','submitted_at','hint_level','native_exit','first_result','evidence','sha256','retrieval_at','retrieval_result','retrieval_evidence','retrieval_sha256')){if([string]::IsNullOrWhiteSpace([string]$row.$field)){throw "blank $field problem=$($row.problem_id)"}} | 실행 의미: 현재 bytes를 64자리 digest로 evidence에 결박한다. |
| 81 | if($expectedMocks -cnotcontains $row.mock_id){throw "unknown mock: $($row.mock_id)"} | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 82 | if($denied -ccontains $row.problem_id){throw "known guided/pre-exposed problem ID collision: $($row.problem_id)"} | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 83 | if($historyIds -ccontains $row.problem_id){throw "prior sealed problem ID collision: $($row.problem_id)"} | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 84 | if(@($exposures|Where-Object {$_.problem_id -ceq $row.problem_id}).Count){throw "pre-attempt exposure collision: $($row.problem_id)"} | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 85 | if(@('algorithm','SQL') -cnotcontains $row.kind){throw "kind must be algorithm|SQL: $($row.problem_id)"} | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 86 | $uri=$null;if(![uri]::TryCreate($row.source_url,[UriKind]::Absolute,[ref]$uri) -or $uri.Scheme -cne 'https' -or $uri.DnsSafeHost -cne 'school.programmers.co.kr' -or $uri.AbsolutePath -cnotmatch '^/learn/courses/[0-9]+/lessons/([0-9]+)/?$'){throw "unapproved problem source: $($row.problem_id)"};$lessonId=[regex]::Match($uri.AbsolutePath,'/lessons/([0-9]+)').Groups[1].Value;if($row.problem_id -cne ('P'+$lessonId)){throw "problem_id/source lesson mismatch: $($row.problem_id) vs P$lessonId"} | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 87 | if($row.exposure_class -cne 'sealed_first_pass'){throw "pre-exposed/ineligible item: $($row.problem_id)"} | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 88 | if($row.hint_level -cne 'NONE'){throw "hinted item is not first-pass eligible: $($row.problem_id)"} | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 89 | if($row.native_exit -cne '0' -or @('PASS','FAIL') -cnotcontains $row.first_result){throw "native exit/result invalid: $($row.problem_id)"} | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 90 | foreach($timeField in @('source_checked_at','revealed_at','started_at','submitted_at')){if([string]$row.$timeField -cnotmatch '(?:Z|[+-][0-9]{2}:[0-9]{2})$'){throw "timezone required $timeField problem=$($row.problem_id)"}} | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 91 | $checked=[datetimeoffset]::MinValue;$reveal=[datetimeoffset]::MinValue;$start=[datetimeoffset]::MinValue;$submit=[datetimeoffset]::MinValue | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 92 | if(![datetimeoffset]::TryParse($row.source_checked_at,[ref]$checked)){throw "invalid source_checked_at: $($row.problem_id)"} | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 93 | if(![datetimeoffset]::TryParse($row.revealed_at,[Globalization.CultureInfo]::InvariantCulture,[Globalization.DateTimeStyles]::RoundtripKind,[ref]$reveal)){throw "invalid revealed_at: $($row.problem_id)"} | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 94 | if(![datetimeoffset]::TryParse($row.started_at,[Globalization.CultureInfo]::InvariantCulture,[Globalization.DateTimeStyles]::RoundtripKind,[ref]$start)){throw "invalid started_at: $($row.problem_id)"} | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 95 | if(![datetimeoffset]::TryParse($row.submitted_at,[Globalization.CultureInfo]::InvariantCulture,[Globalization.DateTimeStyles]::RoundtripKind,[ref]$submit)){throw "invalid submitted_at: $($row.problem_id)"} | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 96 | if($checked -ne $reveal -or $reveal -ne $start -or $submit -le $start -or ($submit-$start).TotalMinutes -gt 150){throw "source/reveal/start/submit timing invalid: $($row.problem_id)"} | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 97 | foreach($pair in @(@($row.source_evidence,$row.source_sha256,'source'),@($row.evidence,$row.sha256,'first'))){if(!(Test-Path -LiteralPath $pair[0] -PathType Leaf) -or (Get-Item -LiteralPath $pair[0]).Length -eq 0){throw "missing/empty $($pair[2]) evidence: $($row.problem_id)"};$h=(Get-FileHash -Algorithm SHA256 -LiteralPath $pair[0]).Hash.ToLowerInvariant();if($pair[1] -cnotmatch '^[0-9a-fA-F]{64}$' -or $h -cne $pair[1].ToLowerInvariant()){throw "$($pair[2]) evidence hash mismatch: $($row.problem_id)"}} | 실행 의미: 현재 bytes를 64자리 digest로 evidence에 결박한다. |
| 98 | $null=Assert-SealedPromptContract $row;$null=Assert-SealedFirstEvidence $row | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 99 | if($row.first_result -ceq 'PASS'){if(@($row.retrieval_at,$row.retrieval_result,$row.retrieval_evidence,$row.retrieval_sha256)|Where-Object {$_ -cne 'N-A_FAST_TRACK'}){throw "PASS item must use exact N-A_FAST_TRACK retrieval tuple: $($row.problem_id)"}}else{ | 실행 의미: 현재 bytes를 64자리 digest로 evidence에 결박한다. |
| 100 | $retrievalTuple=@($row.retrieval_at,$row.retrieval_result,$row.retrieval_evidence,$row.retrieval_sha256);$pendingFields=@($retrievalTuple|Where-Object {$_ -ceq 'PENDING_D+2'}).Count;if($pendingFields){if($pendingFields -ne 4){throw "mixed pending retrieval tuple: $($row.problem_id)"};if($requireRetrieval){throw "D+2 retrieval still pending: $($row.problem_id)"};$pending++;continue} | 실행 의미: 현재 bytes를 64자리 digest로 evidence에 결박한다. |
| 101 | if(@($retrievalTuple|Where-Object {$_ -ceq 'N-A_FAST_TRACK'}).Count){throw "FAIL item cannot fast-track retrieval: $($row.problem_id)"};if($row.retrieval_result -cnotin @('PASS','FAIL')){throw "invalid retrieval_result: $($row.problem_id)"};$retry=[datetimeoffset]::MinValue;if($row.retrieval_at -cnotmatch '(?:Z|[+-][0-9]{2}:[0-9]{2})$' -or ![datetimeoffset]::TryParse($row.retrieval_at,[ref]$retry) -or ($retry-$submit).TotalHours -lt 46 -or ($retry-$submit).TotalHours -gt 74){throw "D+2 retrieval window must be 46-74h: $($row.problem_id)"};if(!(Test-Path -LiteralPath $row.retrieval_evidence -PathType Leaf) -or (Get-Item -LiteralPath $row.retrieval_evidence).Length -eq 0){throw "missing/empty retrieval evidence: $($row.problem_id)"};$rh=(Get-FileHash -Algorithm SHA256 -LiteralPath $row.retrieval_evidence).Hash.ToLowerInvariant();if($row.retrieval_sha256 -cnotmatch '^[0-9a-fA-F]{64}$' -or $rh -cne $row.retrieval_sha256.ToLowerInvariant()){throw "retrieval evidence hash mismatch: $($row.problem_id)"};"--- RETRIEVAL CONTRACT problem=$($row.problem_id) prompt_sha256=$($row.source_sha256) ---";Get-Content -Encoding utf8 -LiteralPath $row.source_evidence;$null=Assert-SealedRetrievalEvidence $row | 실행 의미: 현재 bytes를 64자리 digest로 evidence에 결박한다. |
| 102 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 103 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 104 | foreach($mock in $expectedMocks){$m=@($rows|Where-Object {$_.mock_id -ceq $mock});$alg=@($m|Where-Object {$_.kind -ceq 'algorithm'});$sql=@($m|Where-Object {$_.kind -ceq 'SQL'});if($m.Count -ne 4 -or $alg.Count -ne 3 -or $sql.Count -ne 1){throw "$mock must be exact 3 algorithm + 1 SQL"};$starts=@($m.started_at|Select-Object -Unique);$submits=@($m.submitted_at|Select-Object -Unique);if($starts.Count -ne 1 -or $submits.Count -ne 1){throw "$mock timestamps must be one shared attempt window"}} | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 105 | if($pending -gt 0){'PASS_FIRST_ATTEMPT W25 mocks=1 composition=3+1 contract_scope=STRUCTURE_HASH_TIMING official_result=USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED pending_D+2='+$pending}else{'PASS_LONG_TERM W25 mocks=1 composition=3+1 contract_scope=RETRIEVAL_STRUCTURE_HASH_TIMING official_result=USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED'} | 실행 의미: W25-D6-sealed-first-pass.ps1의 다음 검증 또는 설명 단계를 구성한다. |
STEP 07 / 13
기존 수준의 한 줄 읽기·문법 해부
쉬운 설명 다음에 문법과 실행 순서를 정밀하게 읽습니다.
한 줄로 읽기W25-S1 sealed first pass — 알고리즘 3 + SQL 1는 풀이 전 prompt를 봉인하고 exactly four rows·3 algorithm+1 SQL·shared 150m·10/16/19-field evidence 계약과 user-attested official 경계를 검증한다.
문법 해부
- .ps1 문법에서 선언·조건·pipeline·block 경계를 먼저 나눈다.
- manifest의 finalState와 packaged progressive test의 1_000→700/300 oracle을 서로 다른 계약으로 읽는다.
- phase state·native exit·JUnit XML hash·보존된 XML bytes·사람 판정·USER_ATTESTED external status를 서로 대체하지 않는다.
실행 순서
- 기본 트랙은 SECURITIES(증권)이며, 명시적 CARD 선택은 기본값을 덮어쓴다. 실제 실행 전 최종 선택 한 개를 selected-track.csv·근거·state에 같은 값으로 기록하고 서로 다른 reference/learner root를 확인한다.
- Prepare→VerifyStarter→RecordRed→VerifySolution→RecordGreen→Cumulative→Review 순서를 지킨다.
- test를 소유한 세 phase에서만 native exit와 exact JUnit XML 수치를 판정한다.
- 다음 cleanTest 전에 XML bytes를 고유 경로에 보존하고 runtime history hash와 다시 묶는다. Review·Q41·sealed official evidence는 각자의 별도 owner와 검증 수준으로 남긴다.
W25 조각별 정밀 해설
F18-C01 · 원문 1–12줄
- 문법 해부
- .ps1 문법으로 1–12줄의 선언·조건·phase·assert block을 나눈다.
- 실제 값 추적
- W25-S1, 3 algorithm + 1 SQL, shared ≤150m를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- 기본 SECURITIES 또는 명시적으로 덮어쓴 CARD 중 최종 선택 한 개의 selected-track evidence와 runtime 결과에서 expected와 actual이 일치하고 owner evidence가 같은 run/hash 및 보존 XML에 연결되는 경우다. 기본/덮어쓰기 표시만 있고 실행 evidence가 없으면 NOT_RUN이다.
- 틀린 예·반례
- local validator는 official site에 로그인하지 않는다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- phase 이름·manifest finalState·history hash·exit0 하나를 W25 증거 전체와 같다고 보지 않는다.
- 하지 않는 일
- local validator는 official site에 로그인하지 않는다; ACCEPTED/REJECTED는 USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED다; evaluator independence를 완전 증명하지 않는다; reference와 learner root는 서로 달라야 한다; 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다; 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
- 다음 연결
- 다음 조각 또는 F18 evidence 판정으로 상태를 넘긴다.
F18-C02 · 원문 13–24줄
- 문법 해부
- .ps1 문법으로 13–24줄의 선언·조건·phase·assert block을 나눈다.
- 실제 값 추적
- W25-S1, 3 algorithm + 1 SQL, shared ≤150m를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- 기본 SECURITIES 또는 명시적으로 덮어쓴 CARD 중 최종 선택 한 개의 selected-track evidence와 runtime 결과에서 expected와 actual이 일치하고 owner evidence가 같은 run/hash 및 보존 XML에 연결되는 경우다. 기본/덮어쓰기 표시만 있고 실행 evidence가 없으면 NOT_RUN이다.
- 틀린 예·반례
- local validator는 official site에 로그인하지 않는다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- phase 이름·manifest finalState·history hash·exit0 하나를 W25 증거 전체와 같다고 보지 않는다.
- 하지 않는 일
- local validator는 official site에 로그인하지 않는다; ACCEPTED/REJECTED는 USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED다; evaluator independence를 완전 증명하지 않는다; reference와 learner root는 서로 달라야 한다; 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다; 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
- 다음 연결
- 다음 조각 또는 F18 evidence 판정으로 상태를 넘긴다.
F18-C03 · 원문 25–36줄
- 문법 해부
- .ps1 문법으로 25–36줄의 선언·조건·phase·assert block을 나눈다.
- 실제 값 추적
- W25-S1, 3 algorithm + 1 SQL, shared ≤150m를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- 기본 SECURITIES 또는 명시적으로 덮어쓴 CARD 중 최종 선택 한 개의 selected-track evidence와 runtime 결과에서 expected와 actual이 일치하고 owner evidence가 같은 run/hash 및 보존 XML에 연결되는 경우다. 기본/덮어쓰기 표시만 있고 실행 evidence가 없으면 NOT_RUN이다.
- 틀린 예·반례
- local validator는 official site에 로그인하지 않는다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- phase 이름·manifest finalState·history hash·exit0 하나를 W25 증거 전체와 같다고 보지 않는다.
- 하지 않는 일
- local validator는 official site에 로그인하지 않는다; ACCEPTED/REJECTED는 USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED다; evaluator independence를 완전 증명하지 않는다; reference와 learner root는 서로 달라야 한다; 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다; 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
- 다음 연결
- 다음 조각 또는 F18 evidence 판정으로 상태를 넘긴다.
F18-C04 · 원문 37–48줄
- 문법 해부
- .ps1 문법으로 37–48줄의 선언·조건·phase·assert block을 나눈다.
- 실제 값 추적
- W25-S1, 3 algorithm + 1 SQL, shared ≤150m를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- 기본 SECURITIES 또는 명시적으로 덮어쓴 CARD 중 최종 선택 한 개의 selected-track evidence와 runtime 결과에서 expected와 actual이 일치하고 owner evidence가 같은 run/hash 및 보존 XML에 연결되는 경우다. 기본/덮어쓰기 표시만 있고 실행 evidence가 없으면 NOT_RUN이다.
- 틀린 예·반례
- local validator는 official site에 로그인하지 않는다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- phase 이름·manifest finalState·history hash·exit0 하나를 W25 증거 전체와 같다고 보지 않는다.
- 하지 않는 일
- local validator는 official site에 로그인하지 않는다; ACCEPTED/REJECTED는 USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED다; evaluator independence를 완전 증명하지 않는다; reference와 learner root는 서로 달라야 한다; 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다; 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
- 다음 연결
- 다음 조각 또는 F18 evidence 판정으로 상태를 넘긴다.
F18-C05 · 원문 49–60줄
- 문법 해부
- .ps1 문법으로 49–60줄의 선언·조건·phase·assert block을 나눈다.
- 실제 값 추적
- W25-S1, 3 algorithm + 1 SQL, shared ≤150m를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- 기본 SECURITIES 또는 명시적으로 덮어쓴 CARD 중 최종 선택 한 개의 selected-track evidence와 runtime 결과에서 expected와 actual이 일치하고 owner evidence가 같은 run/hash 및 보존 XML에 연결되는 경우다. 기본/덮어쓰기 표시만 있고 실행 evidence가 없으면 NOT_RUN이다.
- 틀린 예·반례
- local validator는 official site에 로그인하지 않는다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- phase 이름·manifest finalState·history hash·exit0 하나를 W25 증거 전체와 같다고 보지 않는다.
- 하지 않는 일
- local validator는 official site에 로그인하지 않는다; ACCEPTED/REJECTED는 USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED다; evaluator independence를 완전 증명하지 않는다; reference와 learner root는 서로 달라야 한다; 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다; 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
- 다음 연결
- 다음 조각 또는 F18 evidence 판정으로 상태를 넘긴다.
F18-C06 · 원문 61–72줄
- 문법 해부
- .ps1 문법으로 61–72줄의 선언·조건·phase·assert block을 나눈다.
- 실제 값 추적
- W25-S1, 3 algorithm + 1 SQL, shared ≤150m를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- 기본 SECURITIES 또는 명시적으로 덮어쓴 CARD 중 최종 선택 한 개의 selected-track evidence와 runtime 결과에서 expected와 actual이 일치하고 owner evidence가 같은 run/hash 및 보존 XML에 연결되는 경우다. 기본/덮어쓰기 표시만 있고 실행 evidence가 없으면 NOT_RUN이다.
- 틀린 예·반례
- local validator는 official site에 로그인하지 않는다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- phase 이름·manifest finalState·history hash·exit0 하나를 W25 증거 전체와 같다고 보지 않는다.
- 하지 않는 일
- local validator는 official site에 로그인하지 않는다; ACCEPTED/REJECTED는 USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED다; evaluator independence를 완전 증명하지 않는다; reference와 learner root는 서로 달라야 한다; 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다; 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
- 다음 연결
- 다음 조각 또는 F18 evidence 판정으로 상태를 넘긴다.
F18-C07 · 원문 73–84줄
- 문법 해부
- .ps1 문법으로 73–84줄의 선언·조건·phase·assert block을 나눈다.
- 실제 값 추적
- W25-S1, 3 algorithm + 1 SQL, shared ≤150m를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- 기본 SECURITIES 또는 명시적으로 덮어쓴 CARD 중 최종 선택 한 개의 selected-track evidence와 runtime 결과에서 expected와 actual이 일치하고 owner evidence가 같은 run/hash 및 보존 XML에 연결되는 경우다. 기본/덮어쓰기 표시만 있고 실행 evidence가 없으면 NOT_RUN이다.
- 틀린 예·반례
- local validator는 official site에 로그인하지 않는다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- phase 이름·manifest finalState·history hash·exit0 하나를 W25 증거 전체와 같다고 보지 않는다.
- 하지 않는 일
- local validator는 official site에 로그인하지 않는다; ACCEPTED/REJECTED는 USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED다; evaluator independence를 완전 증명하지 않는다; reference와 learner root는 서로 달라야 한다; 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다; 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
- 다음 연결
- 다음 조각 또는 F18 evidence 판정으로 상태를 넘긴다.
F18-C08 · 원문 85–96줄
- 문법 해부
- .ps1 문법으로 85–96줄의 선언·조건·phase·assert block을 나눈다.
- 실제 값 추적
- W25-S1, 3 algorithm + 1 SQL, shared ≤150m를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- 기본 SECURITIES 또는 명시적으로 덮어쓴 CARD 중 최종 선택 한 개의 selected-track evidence와 runtime 결과에서 expected와 actual이 일치하고 owner evidence가 같은 run/hash 및 보존 XML에 연결되는 경우다. 기본/덮어쓰기 표시만 있고 실행 evidence가 없으면 NOT_RUN이다.
- 틀린 예·반례
- local validator는 official site에 로그인하지 않는다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- phase 이름·manifest finalState·history hash·exit0 하나를 W25 증거 전체와 같다고 보지 않는다.
- 하지 않는 일
- local validator는 official site에 로그인하지 않는다; ACCEPTED/REJECTED는 USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED다; evaluator independence를 완전 증명하지 않는다; reference와 learner root는 서로 달라야 한다; 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다; 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
- 다음 연결
- 다음 조각 또는 F18 evidence 판정으로 상태를 넘긴다.
F18-C09 · 원문 97–105줄
- 문법 해부
- .ps1 문법으로 97–105줄의 선언·조건·phase·assert block을 나눈다.
- 실제 값 추적
- W25-S1, 3 algorithm + 1 SQL, shared ≤150m를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- 기본 SECURITIES 또는 명시적으로 덮어쓴 CARD 중 최종 선택 한 개의 selected-track evidence와 runtime 결과에서 expected와 actual이 일치하고 owner evidence가 같은 run/hash 및 보존 XML에 연결되는 경우다. 기본/덮어쓰기 표시만 있고 실행 evidence가 없으면 NOT_RUN이다.
- 틀린 예·반례
- local validator는 official site에 로그인하지 않는다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- phase 이름·manifest finalState·history hash·exit0 하나를 W25 증거 전체와 같다고 보지 않는다.
- 하지 않는 일
- local validator는 official site에 로그인하지 않는다; ACCEPTED/REJECTED는 USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED다; evaluator independence를 완전 증명하지 않는다; reference와 learner root는 서로 달라야 한다; 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다; 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
- 다음 연결
- 다음 조각 또는 F18 evidence 판정으로 상태를 넘긴다.
실행 순서 — W25-S1 sealed first pass — 알고리즘 3 + SQL 1
-
3 algorithm + 1 SQL가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 풀이 전 prompt를 봉인하고 exactly four rows·3 algorithm+1 SQL·shared 150m·10/16/19-field evidence 계약과 user-attested official 경계를 검증한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘ACCEPTED/REJECTED는 USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 3 algorithm + 1 SQL와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 08 / 13
실제 값 따라가기
같은 입력값이 어느 줄을 지나 어떤 결과가 되는지 추적합니다.
| 순서 | 들어온 값 | 코드가 하는 일 | 나온 값·상태 | 경계 |
|---|---|---|---|---|
| 입력 | W25-S1 | source 계약에 대입 | F18 실행/설명 시작 상태 | local validator는 official site에 로그인하지 않는다 |
| 검증 | 3 algorithm + 1 SQL | expected와 actual 또는 형식 대조 | 통과 또는 첫 mismatch | ACCEPTED/REJECTED는 USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED다 |
| 증거 | retrieval 19 fields | marker·hash·row를 같은 run에 연결 | 범위가 적힌 evidence 후보 | 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다 |
실제 값 — W25-S1 sealed first pass — 알고리즘 3 + SQL 1
-
shared ≤150m가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 풀이 전 prompt를 봉인하고 exactly four rows·3 algorithm+1 SQL·shared 150m·10/16/19-field evidence 계약과 user-attested official 경계를 검증한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘evaluator independence를 완전 증명하지 않는다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 shared ≤150m와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 09 / 13
Gradle·JUnit XML·PowerShell·SQL 내부에서 벌어지는 일
세 test phase, XML bytes archive, Review, 별도 Q41, USER_ATTESTED sealed 결과의 owner와 증명 범위를 구분합니다.
W25-D6-sealed-first-pass.ps1 bytes와 track·phase·hash 계약을 읽는다.
SECURITIES 기본 선택과 파일 존재·phase 이름만으로 runtime Green을 주장할 수 없다. 실제 selected-track evidence와 실행 결과는 별도다.RecordRed·RecordGreen·Cumulative에서만 native exit와 exact JUnit XML을 만든다.
local validator는 official site에 로그인하지 않는다XML bytes를 고유 파일로 보존하고 history hash와 묶은 뒤, Review는 기존 CumulativeGreen만 인용한다. Q41은 별도 PostgreSQL evidence, sealed official status는 user-attested evidence로 남긴다.
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다첫 실패 경계 — W25-S1 sealed first pass — 알고리즘 3 + SQL 1
-
first 16 fields가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 풀이 전 prompt를 봉인하고 exactly four rows·3 algorithm+1 SQL·shared 150m·10/16/19-field evidence 계약과 user-attested official 경계를 검증한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘reference와 learner root는 서로 달라야 한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 first 16 fields와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 10 / 13
흔한 착각과 틀린 예
그럴듯하지만 틀린 해석을 반례로 고칩니다.
❌ Prepare·VerifyStarter·VerifySolution·Review도 Gradle을 실행해 Green을 만든다.
왜 틀리나 runtime에서 test 실행을 소유하는 phase는 RecordRed·RecordGreen·Cumulative뿐이다.
바르게 읽기 각 phase history의 execution 유무와 mode를 직접 확인한다.
반례 VerifySolution은 solution hash만 검증하므로 새 JUnit XML이 없어야 정상이다.
❌ 기본 트랙이 SECURITIES이므로 CARD도 함께 실행해도 되고, 기본 배지만으로 runtime 선택·실행 증거가 완성된다.
왜 틀리나 W25 계약은 실제 사용자 근거가 있는 선택 트랙 하나와 반대 트랙 leak 부재를 요구한다.
바르게 읽기 기본 선택은 SECURITIES(증권)이며 명시적 CARD 선택은 덮어쓰기다. 실행 전 최종 선택 한 개를 selected-track.csv·근거·state에 같은 값으로 고정한다.
반례 SECURITIES 기본 배지만 보고 test 실행을 주장하거나 두 트랙 test가 함께 보이면 선택 경계를 위반한다.
❌ progressive_contract Green이면 manifest의 finalState 10_000도 증명된다.
왜 틀리나 packaged test는 1_000에서 300을 처리한 700/300만 assert한다.
바르게 읽기 10_000 finalState는 별도 learner test 또는 사람이 결박한 evidence로 증명한다.
반례 runtime은 domainContract.finalState 문자열을 parse하거나 assert하지 않는다.
❌ history에 XML SHA가 있으니 Red·Green·Cumulative XML 원본이 모두 보존됐다.
왜 틀리나 다음 cleanTest가 build/test-results의 이전 XML을 덮어쓰며 state는 bytes를 복사하지 않는다.
바르게 읽기 각 phase 직후 고유 evidence 경로로 원자 복사하고 hash를 history와 대조한다.
반례 RecordGreen 뒤에는 Red XML 경로가 사라질 수 있다.
❌ Review가 새 test를 실행해 CumulativeGreen을 다시 만들고 Q41·sealed official 결과까지 자동 확인한다.
왜 틀리나 Review는 기존 CumulativeGreen을 전제로 review entry와 leak check만 기록한다. Q41은 별도 PostgreSQL 과제이고 sealed official status는 user-attested다.
바르게 읽기 Review에서는 reviewedPhase와 history 증가만 보고, Q41 native evidence와 USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED sealed evidence를 별도로 판정한다.
반례 Review 뒤 phase는 여전히 CumulativeGreen이고 새 execution/XML·Q41 transcript·official login verification이 생기지 않는다.
STEP 11 / 13
이 코드가 보장하지 않는 것
선택 미결정·10_000 finalState·XML 보존·Review/Q41/sealed official truth처럼 이 코드가 책임지지 않는 일을 분리합니다.
local validator는 official site에 로그인하지 않는다
이 책임을 맡는 곳: runtime GateACCEPTED/REJECTED는 USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED다
이 책임을 맡는 곳: external/human reviewevaluator independence를 완전 증명하지 않는다
이 책임을 맡는 곳: release manifestreference와 learner root는 서로 달라야 한다
이 책임을 맡는 곳: 운영 환경증명하지 않는 범위 — W25-S1 sealed first pass — 알고리즘 3 + SQL 1
-
retrieval 19 fields가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 풀이 전 prompt를 봉인하고 exactly four rows·3 algorithm+1 SQL·shared 150m·10/16/19-field evidence 계약과 user-attested official 경계를 검증한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 retrieval 19 fields와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 12 / 13
직접 다시 써보기
뜻 → 조각 → 전체 코드 순서로 다시 씁니다.
1단계 · 뜻부터 복원
- 풀이 전 prompt를 봉인하고 exactly four rows·3 algorithm+1 SQL·shared 150m·10/16/19-field evidence 계약과 user-attested official 경계를 검증한다.
- 핵심 값은 W25-S1, 3 algorithm + 1 SQL, shared ≤150m, first 16 fields, retrieval 19 fields다.
2단계 · 코드 조각 재조립
- 1. PowerShell 오류를 계속 진행하지 않고 중단시키는 기본 정책을 둔다
- 2. 조건·반복·함수의 실행 block을 연다
- 3. 필수 파일이나 경로가 실제로 있는지 확인한다
- 4. 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다
- 5. 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다
- 6. 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다
- 7. W25-D6-sealed-first-pass.ps1의 다음 검증 또는 설명 단계를 구성한다
- 8. 앞에서 연 block 또는 호출 범위를 닫는다
3단계 · 파일 전체 다시 쓰기
illustrative/powershell/W25-D6-sealed-first-pass.ps1을 새 파일에 다시 쓰고 expected·actual·실패·cleanup·비범위를 주석으로 표시한다.
자가 점검
- 비어 있지 않은 모든 source 줄을 한 번씩 읽었나?
- 기본 트랙을 SECURITIES(증권) 하나로 두고 기본 선택·selected-track evidence·runtime Green을 서로 분리했나?
- Review·Q41·USER_ATTESTED sealed 상태를 자동 성공으로 꾸미지 않았나?
- XML bytes archive와 첫 실패·cleanup 책임을 설명할 수 있나?
STEP 13 / 13
전체 원본 source
감사로 고정한 전체 source를 가감 없이 확인합니다.
학습용 예시 전체 확인하기 · 정본 답안 아님 · NOT_RUN
$ErrorActionPreference='Stop'
function Read-ExactSealedKv([string]$Path,[string]$Label,[string[]]$Required){
if(!(Test-Path -LiteralPath $Path -PathType Leaf) -or (Get-Item -LiteralPath $Path).Length -eq 0){throw "missing/empty ${Label}: $Path"}
$raw=Get-Content -Raw -Encoding utf8 -LiteralPath $Path;if($raw -match '(?i)\b(T[O]DO|T[B]D|PLACEHOLDER|UNCONFIRMED)\b|<[^>]+>|__[^_]+__'){throw "placeholder remains in ${Label}: $Path"}
$map=@{};foreach($line in @(Get-Content -Encoding utf8 -LiteralPath $Path)){if([string]::IsNullOrWhiteSpace($line)){continue};if($line -cnotmatch '^([A-Z][A-Z0-9_]*)=(.+)$'){throw "$Label requires exact KEY=value lines: $line"};$key=$Matches[1];$value=$Matches[2].Trim();if($map.ContainsKey($key)){throw "duplicate $Label key=$key"};if([string]::IsNullOrWhiteSpace($value)){throw "blank $Label key=$key"};$map[$key]=$value}
if($map.Count -ne $Required.Count){throw "$Label field count expected=$($Required.Count) actual=$($map.Count)"};foreach($key in $Required){if(!$map.ContainsKey($key)){throw "missing $Label key=$key"}};foreach($key in $map.Keys){if($Required -cnotcontains $key){throw "unknown $Label key=$key"}}
return $map
}
function Assert-SealedPromptContract([object]$Row){
$required=@('PROBLEM_ID','SOURCE_URL','GOAL','INPUT','OUTPUT','SIGNATURE_OR_QUERY','CONSTRAINTS','EXAMPLES','PROMPT_ONLY','SOLUTION_INCLUDED');$prompt=Read-ExactSealedKv ([string]$Row.source_evidence) 'prompt contract' $required
if($prompt.PROBLEM_ID -cne $Row.problem_id){throw "prompt problem mismatch expected=$($Row.problem_id) actual=$($prompt.PROBLEM_ID)"};if($prompt.SOURCE_URL -cne $Row.source_url){throw "prompt source URL mismatch problem=$($Row.problem_id)"}
if($prompt.PROMPT_ONLY -cne 'true' -or $prompt.SOLUTION_INCLUDED -cne 'false'){throw "prompt-only flags invalid problem=$($Row.problem_id)"}
$actual=(Get-FileHash -Algorithm SHA256 -LiteralPath $Row.source_evidence).Hash.ToLowerInvariant();if($Row.source_sha256 -cnotmatch '^[0-9a-fA-F]{64}$' -or $actual -cne $Row.source_sha256.ToLowerInvariant()){throw "prompt contract hash mismatch problem=$($Row.problem_id)"}
}
function Assert-SealedFirstEvidence([object]$Row){
$required=@('PROBLEM_ID','ATTEMPT','NATIVE_EXIT','NATIVE_COMMAND','NATIVE_TRANSCRIPT','NATIVE_TRANSCRIPT_SHA256','SOLUTION_ARTIFACT','SOLUTION_SHA256','OFFICIAL_SUBMISSION_SNAPSHOT','OFFICIAL_SUBMISSION_SHA256','OFFICIAL_SUBMISSION_URL','OFFICIAL_SUBMISSION_ID','OFFICIAL_STATUS','OFFICIAL_ATTESTATION','VERIFICATION_LEVEL','WITHOUT_MATERIALS');$manifest=Read-ExactSealedKv ([string]$Row.evidence) 'first-attempt manifest' $required
if($manifest.PROBLEM_ID -cne $Row.problem_id -or $manifest.ATTEMPT -cne 'FIRST' -or $manifest.NATIVE_EXIT -cne '0' -or $manifest.WITHOUT_MATERIALS -cne 'true'){throw "first-attempt identity/native contract mismatch problem=$($Row.problem_id)"}
$expectedStatus=if($Row.first_result -ceq 'PASS'){'ACCEPTED'}else{'REJECTED'};$expectedAttestation=if($Row.first_result -ceq 'PASS'){'USER_ATTESTED_OFFICIAL_ACCEPTED'}else{'USER_ATTESTED_OFFICIAL_REJECTED'};if($manifest.OFFICIAL_STATUS -cne $expectedStatus -or $manifest.OFFICIAL_ATTESTATION -cne $expectedAttestation -or $manifest.VERIFICATION_LEVEL -cne 'USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED'){throw "first-attempt official status/attestation mismatch problem=$($Row.problem_id)"}
$officialUri=$null;if(![uri]::TryCreate($manifest.OFFICIAL_SUBMISSION_URL,[UriKind]::Absolute,[ref]$officialUri) -or $officialUri.Scheme -cne 'https' -or $officialUri.DnsSafeHost -cne 'school.programmers.co.kr'){throw "first-attempt official submission URL must use approved host problem=$($Row.problem_id)"};if($manifest.OFFICIAL_SUBMISSION_ID -cnotmatch '^[A-Za-z0-9_-]{6,100}$'){throw "first-attempt official submission ID format invalid problem=$($Row.problem_id)"}
$nativeTranscript=[string]$manifest.NATIVE_TRANSCRIPT;$solution=[string]$manifest.SOLUTION_ARTIFACT;$officialSnapshot=[string]$manifest.OFFICIAL_SUBMISSION_SNAPSHOT;foreach($pair in @(@($nativeTranscript,$manifest.NATIVE_TRANSCRIPT_SHA256,'first native transcript'),@($solution,$manifest.SOLUTION_SHA256,'first solution'),@($officialSnapshot,$manifest.OFFICIAL_SUBMISSION_SHA256,'first official snapshot'))){if(!(Test-Path -LiteralPath $pair[0] -PathType Leaf) -or (Get-Item -LiteralPath $pair[0]).Length -eq 0){throw "missing/empty $($pair[2]) problem=$($Row.problem_id)"};$h=(Get-FileHash -Algorithm SHA256 -LiteralPath $pair[0]).Hash.ToLowerInvariant();if($pair[1] -cnotmatch '^[0-9a-fA-F]{64}$' -or $h -cne $pair[1].ToLowerInvariant()){throw "$($pair[2]) hash mismatch problem=$($Row.problem_id)"}}
$paths=@($Row.source_evidence,$Row.evidence,$nativeTranscript,$solution,$officialSnapshot)|ForEach-Object{[IO.Path]::GetFullPath([string]$_).ToLowerInvariant()};if(@($paths|Select-Object -Unique).Count -ne 5){throw "prompt, first manifest, native transcript, solution and official snapshot must use five distinct paths problem=$($Row.problem_id)"}
$nativeBody=Get-Content -Raw -Encoding utf8 -LiteralPath $nativeTranscript;foreach($token in @("PROBLEM_ID=$($Row.problem_id)",'ATTEMPT=FIRST',"COMMAND=$($manifest.NATIVE_COMMAND)",'EXIT=0')){if(!$nativeBody.Contains($token)){throw "first native transcript token missing problem=$($Row.problem_id) token=$token"}}
$officialBody=Get-Content -Raw -Encoding utf8 -LiteralPath $officialSnapshot;foreach($token in @("PROBLEM_ID=$($Row.problem_id)",'ATTEMPT=FIRST',"STATUS=$expectedStatus","OFFICIAL_SUBMISSION_URL=$($manifest.OFFICIAL_SUBMISSION_URL)","OFFICIAL_SUBMISSION_ID=$($manifest.OFFICIAL_SUBMISSION_ID)","OFFICIAL_ATTESTATION=$expectedAttestation",'VERIFICATION_LEVEL=USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED')){if(!$officialBody.Contains($token)){throw "first official snapshot token missing problem=$($Row.problem_id) token=$token"}}
}
function Assert-SealedRetrievalEvidence([object]$Row){
$required=@('PROBLEM_ID','ATTEMPT','PROMPT_SHA256','RETRIEVAL_AT','RESULT','NATIVE_EXIT','NATIVE_COMMAND','NATIVE_TRANSCRIPT','NATIVE_TRANSCRIPT_SHA256','SOLUTION_ARTIFACT','SOLUTION_SHA256','SUBMISSION_EVIDENCE','SUBMISSION_SHA256','OFFICIAL_SUBMISSION_URL','OFFICIAL_SUBMISSION_ID','OFFICIAL_STATUS','OFFICIAL_ATTESTATION','VERIFICATION_LEVEL','WITHOUT_MATERIALS');$manifest=Read-ExactSealedKv ([string]$Row.retrieval_evidence) 'retrieval manifest' $required
if($manifest.PROBLEM_ID -cne $Row.problem_id -or $manifest.ATTEMPT -cne 'RETRIEVAL'){throw "retrieval identity mismatch problem=$($Row.problem_id)"}
if($manifest.PROMPT_SHA256.ToLowerInvariant() -cne $Row.source_sha256.ToLowerInvariant()){throw "retrieval prompt hash mismatch problem=$($Row.problem_id)"};if($manifest.RETRIEVAL_AT -cne $Row.retrieval_at -or $manifest.RESULT -cne $Row.retrieval_result){throw "retrieval registry/manifest mismatch problem=$($Row.problem_id)"}
if($manifest.NATIVE_EXIT -cne '0' -or $manifest.WITHOUT_MATERIALS -cne 'true'){throw "retrieval must be a native, without-materials attempt problem=$($Row.problem_id)"}
$expectedStatus=if($Row.retrieval_result -ceq 'PASS'){'ACCEPTED'}else{'REJECTED'};$expectedAttestation=if($Row.retrieval_result -ceq 'PASS'){'USER_ATTESTED_OFFICIAL_ACCEPTED'}else{'USER_ATTESTED_OFFICIAL_REJECTED'};if($manifest.OFFICIAL_STATUS -cne $expectedStatus -or $manifest.OFFICIAL_ATTESTATION -cne $expectedAttestation){throw "retrieval official status/attestation mismatch problem=$($Row.problem_id)"};if($manifest.VERIFICATION_LEVEL -cne 'USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED'){throw "retrieval verification level must disclose non-automatic official verification problem=$($Row.problem_id)"}
$officialUri=$null;if(![uri]::TryCreate($manifest.OFFICIAL_SUBMISSION_URL,[UriKind]::Absolute,[ref]$officialUri) -or $officialUri.Scheme -cne 'https' -or $officialUri.DnsSafeHost -cne 'school.programmers.co.kr'){throw "official submission URL must use the approved host problem=$($Row.problem_id)"};if($manifest.OFFICIAL_SUBMISSION_ID -cnotmatch '^[A-Za-z0-9_-]{6,100}$'){throw "official submission ID format invalid problem=$($Row.problem_id)"}
$nativeTranscript=[string]$manifest.NATIVE_TRANSCRIPT;$solution=[string]$manifest.SOLUTION_ARTIFACT;$submission=[string]$manifest.SUBMISSION_EVIDENCE;foreach($pair in @(@($nativeTranscript,$manifest.NATIVE_TRANSCRIPT_SHA256,'native public-harness transcript'),@($solution,$manifest.SOLUTION_SHA256,'retrieval solution'),@($submission,$manifest.SUBMISSION_SHA256,'official submission snapshot'))){if(!(Test-Path -LiteralPath $pair[0] -PathType Leaf) -or (Get-Item -LiteralPath $pair[0]).Length -eq 0){throw "missing/empty $($pair[2]) problem=$($Row.problem_id)"};$h=(Get-FileHash -Algorithm SHA256 -LiteralPath $pair[0]).Hash.ToLowerInvariant();if($pair[1] -cnotmatch '^[0-9a-fA-F]{64}$' -or $h -cne $pair[1].ToLowerInvariant()){throw "$($pair[2]) hash mismatch problem=$($Row.problem_id)"}}
$paths=@($Row.source_evidence,$Row.evidence,$Row.retrieval_evidence,$nativeTranscript,$solution,$submission)|ForEach-Object{[IO.Path]::GetFullPath([string]$_).ToLowerInvariant()};if(@($paths|Select-Object -Unique).Count -ne 6){throw "prompt, first attempt, retrieval manifest, native transcript, solution and official snapshot must use six distinct paths problem=$($Row.problem_id)"}
$nativeBody=Get-Content -Raw -Encoding utf8 -LiteralPath $nativeTranscript;foreach($token in @("PROBLEM_ID=$($Row.problem_id)",'ATTEMPT=RETRIEVAL',"COMMAND=$($manifest.NATIVE_COMMAND)",'EXIT=0')){if(!$nativeBody.Contains($token)){throw "native retrieval transcript token missing problem=$($Row.problem_id) token=$token"}}
$submissionBody=Get-Content -Raw -Encoding utf8 -LiteralPath $submission;foreach($token in @("PROBLEM_ID=$($Row.problem_id)",'ATTEMPT=RETRIEVAL',"STATUS=$expectedStatus","OFFICIAL_SUBMISSION_URL=$($manifest.OFFICIAL_SUBMISSION_URL)","OFFICIAL_SUBMISSION_ID=$($manifest.OFFICIAL_SUBMISSION_ID)","OFFICIAL_ATTESTATION=$expectedAttestation",'VERIFICATION_LEVEL=USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED')){if(!$submissionBody.Contains($token)){throw "official retrieval snapshot token missing problem=$($Row.problem_id) token=$token"}};$statusMatches=[regex]::Matches($submissionBody,'(?m)^STATUS=([A-Z_]+)\s*$');if($statusMatches.Count -ne 1 -or $statusMatches[0].Groups[1].Value -cne $expectedStatus){throw "official retrieval snapshot must contain one exact status problem=$($Row.problem_id)"}
$actualManifest=(Get-FileHash -Algorithm SHA256 -LiteralPath $Row.retrieval_evidence).Hash.ToLowerInvariant();if($Row.retrieval_sha256 -cnotmatch '^[0-9a-fA-F]{64}$' -or $actualManifest -cne $Row.retrieval_sha256.ToLowerInvariant()){throw "retrieval manifest hash mismatch problem=$($Row.problem_id)"}
}
$p='evidence/w25/sealed-first-pass.csv'
$exposurePath='evidence/w25/pre-attempt-exposure.csv'
foreach($file in @($p,$exposurePath)){if(!(Test-Path -LiteralPath $file -PathType Leaf)){throw "BLOCKED_BY_EVALUATOR: missing registry $file"};$body=Get-Content -Raw -LiteralPath $file;if([string]::IsNullOrWhiteSpace($body)){throw "empty registry $file"};if($body -match '(?i)\b(T[O]DO|T[B]D|PLACEHOLDER)\b|<[^>]+>|__[^_]+__'){throw "placeholder registry $file"}}
$header='mock_id,problem_id,kind,source_url,source_checked_at,source_evidence,source_sha256,exposure_class,revealed_at,started_at,submitted_at,hint_level,native_exit,first_result,evidence,sha256,retrieval_at,retrieval_result,retrieval_evidence,retrieval_sha256'
if((Get-Content -LiteralPath $p -TotalCount 1) -cne $header){throw 'sealed registry exact header mismatch'}
$exposureHeader='problem_id,first_exposed_at,exposure_class,evidence';if((Get-Content -LiteralPath $exposurePath -TotalCount 1) -cne $exposureHeader){throw 'pre-attempt exposure exact header mismatch'}
$expectedHistoryWeeks=@()
$historyRows=@()
foreach($priorWeek in $expectedHistoryWeeks){
$historyPath=('evidence/w{0:D2}/sealed-first-pass.csv' -f [int]$priorWeek)
if(!(Test-Path -LiteralPath $historyPath -PathType Leaf)){throw "missing immutable sealed history week=W$priorWeek path=$historyPath"}
$expectedHistoryHeader=if([int]$priorWeek -ge 47){'mock_id,problem_id,kind,category,source_url,source_checked_at,source_evidence,source_sha256,exposure_class,revealed_at,started_at,submitted_at,hint_level,native_exit,first_result,evidence,sha256,retrieval_at,retrieval_result,retrieval_evidence,retrieval_sha256'}else{'mock_id,problem_id,kind,source_url,source_checked_at,source_evidence,source_sha256,exposure_class,revealed_at,started_at,submitted_at,hint_level,native_exit,first_result,evidence,sha256,retrieval_at,retrieval_result,retrieval_evidence,retrieval_sha256'}
if((Get-Content -LiteralPath $historyPath -TotalCount 1) -cne $expectedHistoryHeader){throw "sealed history header mismatch week=W$priorWeek"}
$priorRows=@(Import-Csv -LiteralPath $historyPath);$expectedPriorCount=if([int]$priorWeek -ge 47){10}else{4}
if($priorRows.Count -ne $expectedPriorCount){throw "sealed history row count mismatch week=W$priorWeek expected=$expectedPriorCount actual=$($priorRows.Count)"}
if($priorRows|Group-Object problem_id|Where-Object Count -ne 1){throw "duplicate problem ID inside sealed history week=W$priorWeek"}
foreach($priorRow in $priorRows){
foreach($field in @('problem_id','source_url','source_evidence','source_sha256','exposure_class','evidence','sha256')){if([string]::IsNullOrWhiteSpace([string]$priorRow.$field)){throw "blank sealed history $field week=W$priorWeek"}}
$historyUri=$null;if(![uri]::TryCreate($priorRow.source_url,[UriKind]::Absolute,[ref]$historyUri) -or $historyUri.Scheme -cne 'https' -or $historyUri.DnsSafeHost -cne 'school.programmers.co.kr' -or $historyUri.AbsolutePath -cnotmatch '^/learn/courses/[0-9]+/lessons/([0-9]+)/?$'){throw "unapproved sealed history source week=W$priorWeek problem=$($priorRow.problem_id)"};$historyLessonId=[regex]::Match($historyUri.AbsolutePath,'/lessons/([0-9]+)').Groups[1].Value;if($priorRow.problem_id -cne ('P'+$historyLessonId)){throw "sealed history problem/source mismatch week=W$priorWeek problem=$($priorRow.problem_id)"}
if($priorRow.exposure_class -cne 'sealed_first_pass'){throw "ineligible sealed history exposure class week=W$priorWeek problem=$($priorRow.problem_id)"}
foreach($pair in @(@($priorRow.source_evidence,$priorRow.source_sha256,'source'),@($priorRow.evidence,$priorRow.sha256,'first'))){if(!(Test-Path -LiteralPath $pair[0] -PathType Leaf) -or (Get-Item -LiteralPath $pair[0]).Length -eq 0){throw "missing/empty sealed history $($pair[2]) evidence week=W$priorWeek problem=$($priorRow.problem_id)"};$historyHash=(Get-FileHash -Algorithm SHA256 -LiteralPath $pair[0]).Hash.ToLowerInvariant();if($pair[1] -cnotmatch '^[0-9a-fA-F]{64}$' -or $historyHash -cne $pair[1].ToLowerInvariant()){throw "sealed history $($pair[2]) evidence hash mismatch week=W$priorWeek problem=$($priorRow.problem_id)"}}
$null=Assert-SealedPromptContract $priorRow;$null=Assert-SealedFirstEvidence $priorRow
}
$historyRows+=@($priorRows)
}
if($historyRows|Group-Object problem_id|Where-Object Count -ne 1){throw 'problem ID reused across prior sealed weeks'}
$historyIds=@($historyRows|ForEach-Object {$_.problem_id})
$allRows=@(Import-Csv -LiteralPath $p)
$canonicalCurrentMocks=@('W25-S1')
if($allRows|Where-Object {$canonicalCurrentMocks -cnotcontains $_.mock_id}){throw 'sealed current file contains unknown mock'}
if($allRows|Group-Object problem_id|Where-Object Count -ne 1){throw 'duplicate problem ID across current sealed mocks'}
foreach($currentGroup in @($allRows|Group-Object mock_id)){if($currentGroup.Count -ne 4){throw "partial current mock=$($currentGroup.Name) rows=$($currentGroup.Count) expected=4"}}
$rows=@($allRows|Where-Object {$_.mock_id -cin @('W25-S1')})
$exposures=@(Import-Csv -LiteralPath $exposurePath)
if($rows.Count -ne 4){throw "sealed registry requires exactly 4 rows; actual=$($rows.Count)"}
if($rows|Group-Object problem_id|Where-Object Count -ne 1){throw 'duplicate/pre-exposed problem ID collision'}
if($exposures|Group-Object problem_id|Where-Object Count -ne 1){throw 'duplicate pre-attempt exposure problem_id'}
foreach($x in $exposures){foreach($field in @('problem_id','first_exposed_at','exposure_class','evidence')){if([string]::IsNullOrWhiteSpace([string]$x.$field)){throw "blank exposure $field"}};if($x.first_exposed_at -cnotmatch '(?:Z|[+-][0-9]{2}:[0-9]{2})$'){throw "exposure timezone required: $($x.problem_id)"};if(@('textbook_exposed','guided_timed_re_solve','prior_attempt','public_solution') -cnotcontains $x.exposure_class){throw "unknown prior exposure class: $($x.exposure_class)"};if(!(Test-Path -LiteralPath $x.evidence -PathType Leaf) -or (Get-Item -LiteralPath $x.evidence).Length -eq 0){throw "missing/empty exposure evidence: $($x.problem_id)"}}
$denied=@('FCL-SQL-41','FCL-SQL-42','FCL-SQL-43','P12909','P12939','P12941','P12945','P12951','P12981','P131533','P151136','P1844','P42576','P42577','P42578','P42586','P42746','P42839','P42842','P42883','P42885','P43162','P43165','P59412','P87946')
$expectedMocks=@('W25-S1')
$requireRetrieval=$false;$pending=0
foreach($row in $rows){
foreach($field in @('mock_id','problem_id','kind','source_url','source_checked_at','source_evidence','source_sha256','exposure_class','revealed_at','started_at','submitted_at','hint_level','native_exit','first_result','evidence','sha256','retrieval_at','retrieval_result','retrieval_evidence','retrieval_sha256')){if([string]::IsNullOrWhiteSpace([string]$row.$field)){throw "blank $field problem=$($row.problem_id)"}}
if($expectedMocks -cnotcontains $row.mock_id){throw "unknown mock: $($row.mock_id)"}
if($denied -ccontains $row.problem_id){throw "known guided/pre-exposed problem ID collision: $($row.problem_id)"}
if($historyIds -ccontains $row.problem_id){throw "prior sealed problem ID collision: $($row.problem_id)"}
if(@($exposures|Where-Object {$_.problem_id -ceq $row.problem_id}).Count){throw "pre-attempt exposure collision: $($row.problem_id)"}
if(@('algorithm','SQL') -cnotcontains $row.kind){throw "kind must be algorithm|SQL: $($row.problem_id)"}
$uri=$null;if(![uri]::TryCreate($row.source_url,[UriKind]::Absolute,[ref]$uri) -or $uri.Scheme -cne 'https' -or $uri.DnsSafeHost -cne 'school.programmers.co.kr' -or $uri.AbsolutePath -cnotmatch '^/learn/courses/[0-9]+/lessons/([0-9]+)/?$'){throw "unapproved problem source: $($row.problem_id)"};$lessonId=[regex]::Match($uri.AbsolutePath,'/lessons/([0-9]+)').Groups[1].Value;if($row.problem_id -cne ('P'+$lessonId)){throw "problem_id/source lesson mismatch: $($row.problem_id) vs P$lessonId"}
if($row.exposure_class -cne 'sealed_first_pass'){throw "pre-exposed/ineligible item: $($row.problem_id)"}
if($row.hint_level -cne 'NONE'){throw "hinted item is not first-pass eligible: $($row.problem_id)"}
if($row.native_exit -cne '0' -or @('PASS','FAIL') -cnotcontains $row.first_result){throw "native exit/result invalid: $($row.problem_id)"}
foreach($timeField in @('source_checked_at','revealed_at','started_at','submitted_at')){if([string]$row.$timeField -cnotmatch '(?:Z|[+-][0-9]{2}:[0-9]{2})$'){throw "timezone required $timeField problem=$($row.problem_id)"}}
$checked=[datetimeoffset]::MinValue;$reveal=[datetimeoffset]::MinValue;$start=[datetimeoffset]::MinValue;$submit=[datetimeoffset]::MinValue
if(![datetimeoffset]::TryParse($row.source_checked_at,[ref]$checked)){throw "invalid source_checked_at: $($row.problem_id)"}
if(![datetimeoffset]::TryParse($row.revealed_at,[Globalization.CultureInfo]::InvariantCulture,[Globalization.DateTimeStyles]::RoundtripKind,[ref]$reveal)){throw "invalid revealed_at: $($row.problem_id)"}
if(![datetimeoffset]::TryParse($row.started_at,[Globalization.CultureInfo]::InvariantCulture,[Globalization.DateTimeStyles]::RoundtripKind,[ref]$start)){throw "invalid started_at: $($row.problem_id)"}
if(![datetimeoffset]::TryParse($row.submitted_at,[Globalization.CultureInfo]::InvariantCulture,[Globalization.DateTimeStyles]::RoundtripKind,[ref]$submit)){throw "invalid submitted_at: $($row.problem_id)"}
if($checked -ne $reveal -or $reveal -ne $start -or $submit -le $start -or ($submit-$start).TotalMinutes -gt 150){throw "source/reveal/start/submit timing invalid: $($row.problem_id)"}
foreach($pair in @(@($row.source_evidence,$row.source_sha256,'source'),@($row.evidence,$row.sha256,'first'))){if(!(Test-Path -LiteralPath $pair[0] -PathType Leaf) -or (Get-Item -LiteralPath $pair[0]).Length -eq 0){throw "missing/empty $($pair[2]) evidence: $($row.problem_id)"};$h=(Get-FileHash -Algorithm SHA256 -LiteralPath $pair[0]).Hash.ToLowerInvariant();if($pair[1] -cnotmatch '^[0-9a-fA-F]{64}$' -or $h -cne $pair[1].ToLowerInvariant()){throw "$($pair[2]) evidence hash mismatch: $($row.problem_id)"}}
$null=Assert-SealedPromptContract $row;$null=Assert-SealedFirstEvidence $row
if($row.first_result -ceq 'PASS'){if(@($row.retrieval_at,$row.retrieval_result,$row.retrieval_evidence,$row.retrieval_sha256)|Where-Object {$_ -cne 'N-A_FAST_TRACK'}){throw "PASS item must use exact N-A_FAST_TRACK retrieval tuple: $($row.problem_id)"}}else{
$retrievalTuple=@($row.retrieval_at,$row.retrieval_result,$row.retrieval_evidence,$row.retrieval_sha256);$pendingFields=@($retrievalTuple|Where-Object {$_ -ceq 'PENDING_D+2'}).Count;if($pendingFields){if($pendingFields -ne 4){throw "mixed pending retrieval tuple: $($row.problem_id)"};if($requireRetrieval){throw "D+2 retrieval still pending: $($row.problem_id)"};$pending++;continue}
if(@($retrievalTuple|Where-Object {$_ -ceq 'N-A_FAST_TRACK'}).Count){throw "FAIL item cannot fast-track retrieval: $($row.problem_id)"};if($row.retrieval_result -cnotin @('PASS','FAIL')){throw "invalid retrieval_result: $($row.problem_id)"};$retry=[datetimeoffset]::MinValue;if($row.retrieval_at -cnotmatch '(?:Z|[+-][0-9]{2}:[0-9]{2})$' -or ![datetimeoffset]::TryParse($row.retrieval_at,[ref]$retry) -or ($retry-$submit).TotalHours -lt 46 -or ($retry-$submit).TotalHours -gt 74){throw "D+2 retrieval window must be 46-74h: $($row.problem_id)"};if(!(Test-Path -LiteralPath $row.retrieval_evidence -PathType Leaf) -or (Get-Item -LiteralPath $row.retrieval_evidence).Length -eq 0){throw "missing/empty retrieval evidence: $($row.problem_id)"};$rh=(Get-FileHash -Algorithm SHA256 -LiteralPath $row.retrieval_evidence).Hash.ToLowerInvariant();if($row.retrieval_sha256 -cnotmatch '^[0-9a-fA-F]{64}$' -or $rh -cne $row.retrieval_sha256.ToLowerInvariant()){throw "retrieval evidence hash mismatch: $($row.problem_id)"};"--- RETRIEVAL CONTRACT problem=$($row.problem_id) prompt_sha256=$($row.source_sha256) ---";Get-Content -Encoding utf8 -LiteralPath $row.source_evidence;$null=Assert-SealedRetrievalEvidence $row
}
}
foreach($mock in $expectedMocks){$m=@($rows|Where-Object {$_.mock_id -ceq $mock});$alg=@($m|Where-Object {$_.kind -ceq 'algorithm'});$sql=@($m|Where-Object {$_.kind -ceq 'SQL'});if($m.Count -ne 4 -or $alg.Count -ne 3 -or $sql.Count -ne 1){throw "$mock must be exact 3 algorithm + 1 SQL"};$starts=@($m.started_at|Select-Object -Unique);$submits=@($m.submitted_at|Select-Object -Unique);if($starts.Count -ne 1 -or $submits.Count -ne 1){throw "$mock timestamps must be one shared attempt window"}}
if($pending -gt 0){'PASS_FIRST_ATTEMPT W25 mocks=1 composition=3+1 contract_scope=STRUCTURE_HASH_TIMING official_result=USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED pending_D+2='+$pending}else{'PASS_LONG_TERM W25 mocks=1 composition=3+1 contract_scope=RETRIEVAL_STRUCTURE_HASH_TIMING official_result=USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED'}
19D7 Review — 기존 CumulativeGreen을 reviewedPhase로 연결
illustrative/powershell/W25-D7-review.ps1
학습용 예시 · W25 phase wrapper · 정본 답안 아님 · 로컬 미실행 · 학습용 예시 · 정본 답안 아님 · NOT_RUN · W25-F1923줄 연결23줄 번역3 chunks
D7 Review — 기존 CumulativeGreen을 reviewedPhase로 연결
illustrative/powershell/W25-D7-review.ps1
학습용 예시 · W25 phase wrapper · 정본 답안 아님 · 로컬 미실행 · 학습용 예시 · 정본 답안 아님 · NOT_RUN · W25-F19STEP 01 / 13
오늘 이 코드에서 해결할 문제
무엇을 이해해야 하는지 질문부터 잡습니다.
새 Gradle/XML을 만들지 않고 prior CumulativeGreen·leak 경계·history 증가를 확인하며 phase는 CumulativeGreen으로 유지한다.
- Review requires CumulativeGreen은 어느 source와 실제 결과에서 확인해야 할까?
- 첫 실패를 만드는 조건과 fail-closed 지점은 어디일까?
- 왜 ‘Review는 Git commit·audio·설명 의미를 자동 검증하지 않는다’를 별도 경계로 남겨야 할까?
Review requires CumulativeGreenreviewedPhase=CumulativeGreenphase remains CumulativeGreenno new executionruntime_claim=false왜 필요한가 — D7 Review — 기존 CumulativeGreen을 reviewedPhase로 연결
-
Review requires CumulativeGreen가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 새 Gradle/XML을 만들지 않고 prior CumulativeGreen·leak 경계·history 증가를 확인하며 phase는 CumulativeGreen으로 유지한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘Review는 Git commit·audio·설명 의미를 자동 검증하지 않는다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 Review requires CumulativeGreen와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 02 / 13
아주 짧게: 이 코드는 왜 필요할까?
웹소설 대신 이 코드가 필요한 이유만 두 문단으로 쉽게 봅니다.
사용자의 기본 선택에 따라 이 HTML은 SECURITIES(증권)을 주 트랙으로 읽는다. CARD는 비교용이며 명시적으로 고르면 기본값을 덮어쓸 수 있다. 실제 실행은 최종 선택 한 개를 selected-track.csv·근거·state에 같은 값으로 기록하고 reference와 learner 폴더를 분리한 뒤에만 시작한다. 이 HTML 자체는 Gradle/JUnit을 실행하지 않아 NOT_RUN 상태다.
한 통장만 골라 빨강에서 초록까지 증명하는 일주일
이 파일은 새 Gradle/XML을 만들지 않고 prior CumulativeGreen·leak 경계·history 증가를 확인하며 phase는 CumulativeGreen으로 유지한다. 눈으로 읽을 때는 각 줄을 검수표 한 칸처럼 보고, 입력과 다음 상태를 놓치지 않는다.
마지막 도장은 hash 확인, 세 test phase의 실제 JUnit 실행, XML bytes archive, 사람 review를 서로 구분한 뒤에만 찍는다. Review는 새 test가 아니며 Q41은 stage runtime 밖의 별도 NOT_RUN 과제, sealed official status는 USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED다. 특히 Review는 Git commit·audio·설명 의미를 자동 검증하지 않는다
딱 여기까지만 비유와 SECURITIES 기본 배지는 실제 selected-track 근거, Gradle/JUnit 실행, XML bytes 보존, 사람 review, Q41 실행, sealed official 확인을 대신하지 않는다.
STEP 03 / 13
초등학생도 이해하는 설명
생활 비유와 실제 코드의 경계를 함께 확인합니다.
값 1: Review requires CumulativeGreen
이 파일에서 계속 확인할 고정 단서가 Review requires CumulativeGreen다.
- 코드 연결
F19 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- Review는 Git commit·audio·설명 의미를 자동 검증하지 않는다
값 2: reviewedPhase=CumulativeGreen
이 파일에서 계속 확인할 고정 단서가 reviewedPhase=CumulativeGreen다.
- 코드 연결
F19 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- hash는 XML bytes·사람 설명을 대신하지 않는다
값 3: phase remains CumulativeGreen
이 파일에서 계속 확인할 고정 단서가 phase remains CumulativeGreen다.
- 코드 연결
F19 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- reference와 learner root는 서로 달라야 한다
값 4: no new execution
이 파일에서 계속 확인할 고정 단서가 no new execution다.
- 코드 연결
F19 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
값 5: runtime_claim=false
이 파일에서 계속 확인할 고정 단서가 runtime_claim=false다.
- 코드 연결
F19 전체 source와 evidence marker에서 같은 값을 찾는다.- 비유
- 검수표에 미리 인쇄된 숫자나 상태 칸
- 비유의 끝
- 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
STEP 04 / 13
비유 ↔ 코드 전체 연결표
감사 규칙상 연결 대상인 원본 23줄을 빠짐없이 연결합니다.
| 줄 | 정확한 원본 줄 | STARRY 비유 | 실제 뜻·입력·결과·한계 |
|---|---|---|---|
| 1줄F19-L01 | # W25 PDF p48-p52의 Review 흐름을 정리한 학습용 예시다. |
출고표 1번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 기존 CumulativeGreen을 전제로 review entry와 leak 경계만 다시 기록한다.
|
| 2줄F19-L02 | # Review는 새 Gradle/ |
출고표 2번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W25부터 현재 주까지 선택 트랙 selector를 누적 실행하는 phase다.
|
| 3줄F19-L03 | $ErrorActionPreference = |
출고표 3번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 PowerShell 오류를 계속 진행하지 않고 중단시키는 기본 정책을 둔다.
|
| 4줄F19-L04 | $ReferenceRoot = |
출고표 4번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 입력 경로를 실제 절대 경로로 확인한다.
|
| 5줄F19-L05 | $LearnerRoot = |
출고표 5번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 입력 경로를 실제 절대 경로로 확인한다.
|
| 6줄F19-L06 | if ( |
출고표 6번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 조건·반복·함수의 실행 block을 연다.
|
| 7줄F19-L07 | throw 'reference and learner roots must be different' |
출고표 7번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
|
| 8줄F19-L08 | } |
출고표 8번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 9줄F19-L09 | $StatePath = |
출고표 9번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 10줄F19-L10 | $Before = |
출고표 10번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 JSON text를 필드로 접근 가능한 PowerShell object로 바꾼다.
|
| 11줄F19-L11 | if ( |
출고표 11번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W25부터 현재 주까지 선택 트랙 selector를 누적 실행하는 phase다.
|
| 13줄F19-L13 | $Runner = |
출고표 13번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 14줄F19-L14 | & powershell. |
출고표 14번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W25-D7-review.ps1의 다음 검증 또는 설명 단계를 구성한다.
|
| 15줄F19-L15 | -ReferenceRoot $ReferenceRoot -LearnerRoot $LearnerRoot -Week 25 -Phase Review -TimeoutSeconds 1200 |
출고표 15번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 기존 CumulativeGreen을 전제로 review entry와 leak 경계만 다시 기록한다.
|
| 16줄F19-L16 | if ( |
출고표 16번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 기존 CumulativeGreen을 전제로 review entry와 leak 경계만 다시 기록한다.
|
| 18줄F19-L18 | $After = |
출고표 18번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 JSON text를 필드로 접근 가능한 PowerShell object로 바꾼다.
|
| 19줄F19-L19 | $Entry = |
출고표 19번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
|
| 20줄F19-L20 | if ( |
출고표 20번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W25부터 현재 주까지 선택 트랙 selector를 누적 실행하는 phase다.
|
| 21줄F19-L21 | if ( |
출고표 21번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W25부터 현재 주까지 선택 트랙 selector를 누적 실행하는 phase다.
|
| 22줄F19-L22 | throw 'Review must bind prior CumulativeGreen without creating new execution evidence' |
출고표 22번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W25부터 현재 주까지 선택 트랙 selector를 누적 실행하는 phase다.
|
| 23줄F19-L23 | } |
출고표 23번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
|
| 24줄F19-L24 | $Hash = |
출고표 24번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 현재 bytes를 64자리 digest로 evidence에 결박한다.
|
| 25줄F19-L25 | "W25_REVIEW_RECORDED track= |
출고표 25번 칸을 읽어 다음 검사 칸으로 넘기는 장면 | 이 줄은 W25부터 현재 주까지 선택 트랙 selector를 누적 실행하는 phase다.
|
STEP 05 / 13
원본 코드 조각
원본을 3개 의미 조각으로 나누어 그대로 확인합니다.
파일을 한꺼번에 외우지 않고 실행 의미가 이어지는 작은 조각으로 봅니다. 아래 코드는 prompt·fixture·가정을 밝힌 학습용 예시 source이며, 제공 정본 답안이나 실행 결과가 아닌 NOT_RUN 자료입니다.
# W25 PDF p48-p52의 Review 흐름을 정리한 학습용 예시다.
# Review는 새 Gradle/XML을 읽지 않고 기존 CumulativeGreen history와 leak 경계를 다시 확인한다.
$ErrorActionPreference = 'Stop'
$ReferenceRoot = (Resolve-Path -LiteralPath $env:FINANCIAL_IT_REFERENCE_ROOT).Path
$LearnerRoot = (Resolve-Path -LiteralPath $env:FINANCIAL_IT_LEARNER_ROOT).Path
if ([string]::Equals($ReferenceRoot, $LearnerRoot, [StringComparison]::OrdinalIgnoreCase)) {
throw 'reference and learner roots must be different'
}
$StatePath = Join-Path $LearnerRoot '.track-learning-stage.json'
$Before = Get-Content -Raw -LiteralPath $StatePath | ConvertFrom-Json
if ($Before.week -ne 25 -or $Before.phase -cne 'CumulativeGreen') { throw 'Review requires CumulativeGreen' }
$Runner = Join-Path $ReferenceRoot 'scripts\apply-track-learning-stage.ps1'
& powershell.exe -NoProfile -ExecutionPolicy Bypass -File $Runner `
-ReferenceRoot $ReferenceRoot -LearnerRoot $LearnerRoot -Week 25 -Phase Review -TimeoutSeconds 1200
if ($LASTEXITCODE -ne 0) { throw "W25 Review native exit=$LASTEXITCODE" }
$After = Get-Content -Raw -LiteralPath $StatePath | ConvertFrom-Json
$Entry = @($After.history)[-1]
if ($After.phase -cne 'CumulativeGreen' -or $Entry.phase -cne 'Review') { throw 'Review state mismatch' }
if ($Entry.reviewedPhase -cne 'CumulativeGreen' -or $null -ne $Entry.execution) {
throw 'Review must bind prior CumulativeGreen without creating new execution evidence'
}
$Hash = (Get-FileHash -LiteralPath $StatePath -Algorithm SHA256).Hash.ToLowerInvariant()
"W25_REVIEW_RECORDED track=$($After.track) phase=CumulativeGreen runtime_claim=false state_sha256=$Hash"
STEP 06 / 13
코드 한 줄씩 한국어로 번역
비어 있지 않은 23줄을 모두 한국어로 옮깁니다.
비어 있지 않은 원본 줄은 하나도 생략하지 않습니다.
| 줄 | 원본 | 한국어 번역 |
|---|---|---|
| 1 | # W25 PDF p48-p52의 Review 흐름을 정리한 학습용 예시다. | 문서 의미: 기존 CumulativeGreen을 전제로 review entry와 leak 경계만 다시 기록한다. |
| 2 | # Review는 새 Gradle/XML을 읽지 않고 기존 CumulativeGreen history와 leak 경계를 다시 확인한다. | 문서 의미: W25부터 현재 주까지 선택 트랙 selector를 누적 실행하는 phase다. |
| 3 | $ErrorActionPreference = 'Stop' | 실행 의미: PowerShell 오류를 계속 진행하지 않고 중단시키는 기본 정책을 둔다. |
| 4 | $ReferenceRoot = (Resolve-Path -LiteralPath $env:FINANCIAL_IT_REFERENCE_ROOT).Path | 실행 의미: 입력 경로를 실제 절대 경로로 확인한다. |
| 5 | $LearnerRoot = (Resolve-Path -LiteralPath $env:FINANCIAL_IT_LEARNER_ROOT).Path | 실행 의미: 입력 경로를 실제 절대 경로로 확인한다. |
| 6 | if ([string]::Equals($ReferenceRoot, $LearnerRoot, [StringComparison]::OrdinalIgnoreCase)) { | 실행 의미: 조건·반복·함수의 실행 block을 연다. |
| 7 | throw 'reference and learner roots must be different' | 실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다. |
| 8 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 9 | $StatePath = Join-Path $LearnerRoot '.track-learning-stage.json' | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 10 | $Before = Get-Content -Raw -LiteralPath $StatePath | ConvertFrom-Json | 실행 의미: JSON text를 필드로 접근 가능한 PowerShell object로 바꾼다. |
| 11 | if ($Before.week -ne 25 -or $Before.phase -cne 'CumulativeGreen') { throw 'Review requires CumulativeGreen' } | 실행 의미: W25부터 현재 주까지 선택 트랙 selector를 누적 실행하는 phase다. |
| 13 | $Runner = Join-Path $ReferenceRoot 'scripts\apply-track-learning-stage.ps1' | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 14 | & powershell.exe -NoProfile -ExecutionPolicy Bypass -File $Runner ` | 실행 의미: W25-D7-review.ps1의 다음 검증 또는 설명 단계를 구성한다. |
| 15 | -ReferenceRoot $ReferenceRoot -LearnerRoot $LearnerRoot -Week 25 -Phase Review -TimeoutSeconds 1200 | 실행 의미: 기존 CumulativeGreen을 전제로 review entry와 leak 경계만 다시 기록한다. |
| 16 | if ($LASTEXITCODE -ne 0) { throw "W25 Review native exit=$LASTEXITCODE" } | 실행 의미: 기존 CumulativeGreen을 전제로 review entry와 leak 경계만 다시 기록한다. |
| 18 | $After = Get-Content -Raw -LiteralPath $StatePath | ConvertFrom-Json | 실행 의미: JSON text를 필드로 접근 가능한 PowerShell object로 바꾼다. |
| 19 | $Entry = @($After.history)[-1] | 실행 의미: 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다. |
| 20 | if ($After.phase -cne 'CumulativeGreen' -or $Entry.phase -cne 'Review') { throw 'Review state mismatch' } | 실행 의미: W25부터 현재 주까지 선택 트랙 selector를 누적 실행하는 phase다. |
| 21 | if ($Entry.reviewedPhase -cne 'CumulativeGreen' -or $null -ne $Entry.execution) { | 실행 의미: W25부터 현재 주까지 선택 트랙 selector를 누적 실행하는 phase다. |
| 22 | throw 'Review must bind prior CumulativeGreen without creating new execution evidence' | 실행 의미: W25부터 현재 주까지 선택 트랙 selector를 누적 실행하는 phase다. |
| 23 | } | 실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다. |
| 24 | $Hash = (Get-FileHash -LiteralPath $StatePath -Algorithm SHA256).Hash.ToLowerInvariant() | 실행 의미: 현재 bytes를 64자리 digest로 evidence에 결박한다. |
| 25 | "W25_REVIEW_RECORDED track=$($After.track) phase=CumulativeGreen runtime_claim=false state_sha256=$Hash" | 실행 의미: W25부터 현재 주까지 선택 트랙 selector를 누적 실행하는 phase다. |
STEP 07 / 13
기존 수준의 한 줄 읽기·문법 해부
쉬운 설명 다음에 문법과 실행 순서를 정밀하게 읽습니다.
한 줄로 읽기D7 Review — 기존 CumulativeGreen을 reviewedPhase로 연결는 새 Gradle/XML을 만들지 않고 prior CumulativeGreen·leak 경계·history 증가를 확인하며 phase는 CumulativeGreen으로 유지한다.
문법 해부
- .ps1 문법에서 선언·조건·pipeline·block 경계를 먼저 나눈다.
- manifest의 finalState와 packaged progressive test의 1_000→700/300 oracle을 서로 다른 계약으로 읽는다.
- phase state·native exit·JUnit XML hash·보존된 XML bytes·사람 판정·USER_ATTESTED external status를 서로 대체하지 않는다.
실행 순서
- 기본 트랙은 SECURITIES(증권)이며, 명시적 CARD 선택은 기본값을 덮어쓴다. 실제 실행 전 최종 선택 한 개를 selected-track.csv·근거·state에 같은 값으로 기록하고 서로 다른 reference/learner root를 확인한다.
- Prepare→VerifyStarter→RecordRed→VerifySolution→RecordGreen→Cumulative→Review 순서를 지킨다.
- test를 소유한 세 phase에서만 native exit와 exact JUnit XML 수치를 판정한다.
- 다음 cleanTest 전에 XML bytes를 고유 경로에 보존하고 runtime history hash와 다시 묶는다. Review·Q41·sealed official evidence는 각자의 별도 owner와 검증 수준으로 남긴다.
W25 조각별 정밀 해설
F19-C01 · 원문 1–12줄
- 문법 해부
- .ps1 문법으로 1–12줄의 선언·조건·phase·assert block을 나눈다.
- 실제 값 추적
- Review requires CumulativeGreen, reviewedPhase=CumulativeGreen, phase remains CumulativeGreen를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- 기본 SECURITIES 또는 명시적으로 덮어쓴 CARD 중 최종 선택 한 개의 selected-track evidence와 runtime 결과에서 expected와 actual이 일치하고 owner evidence가 같은 run/hash 및 보존 XML에 연결되는 경우다. 기본/덮어쓰기 표시만 있고 실행 evidence가 없으면 NOT_RUN이다.
- 틀린 예·반례
- Review는 Git commit·audio·설명 의미를 자동 검증하지 않는다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- phase 이름·manifest finalState·history hash·exit0 하나를 W25 증거 전체와 같다고 보지 않는다.
- 하지 않는 일
- Review는 Git commit·audio·설명 의미를 자동 검증하지 않는다; hash는 XML bytes·사람 설명을 대신하지 않는다; reference와 learner root는 서로 달라야 한다; 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다; 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
- 다음 연결
- 다음 조각 또는 F19 evidence 판정으로 상태를 넘긴다.
F19-C02 · 원문 13–24줄
- 문법 해부
- .ps1 문법으로 13–24줄의 선언·조건·phase·assert block을 나눈다.
- 실제 값 추적
- Review requires CumulativeGreen, reviewedPhase=CumulativeGreen, phase remains CumulativeGreen를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- 기본 SECURITIES 또는 명시적으로 덮어쓴 CARD 중 최종 선택 한 개의 selected-track evidence와 runtime 결과에서 expected와 actual이 일치하고 owner evidence가 같은 run/hash 및 보존 XML에 연결되는 경우다. 기본/덮어쓰기 표시만 있고 실행 evidence가 없으면 NOT_RUN이다.
- 틀린 예·반례
- Review는 Git commit·audio·설명 의미를 자동 검증하지 않는다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- phase 이름·manifest finalState·history hash·exit0 하나를 W25 증거 전체와 같다고 보지 않는다.
- 하지 않는 일
- Review는 Git commit·audio·설명 의미를 자동 검증하지 않는다; hash는 XML bytes·사람 설명을 대신하지 않는다; reference와 learner root는 서로 달라야 한다; 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다; 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
- 다음 연결
- 다음 조각 또는 F19 evidence 판정으로 상태를 넘긴다.
F19-C03 · 원문 25–25줄
- 문법 해부
- .ps1 문법으로 25–25줄의 선언·조건·phase·assert block을 나눈다.
- 실제 값 추적
- Review requires CumulativeGreen, reviewedPhase=CumulativeGreen, phase remains CumulativeGreen를 입력으로 두고 이 조각 뒤의 actual 상태를 추적한다.
- 정상 예
- 기본 SECURITIES 또는 명시적으로 덮어쓴 CARD 중 최종 선택 한 개의 selected-track evidence와 runtime 결과에서 expected와 actual이 일치하고 owner evidence가 같은 run/hash 및 보존 XML에 연결되는 경우다. 기본/덮어쓰기 표시만 있고 실행 evidence가 없으면 NOT_RUN이다.
- 틀린 예·반례
- Review는 Git commit·audio·설명 의미를 자동 검증하지 않는다인데도 더 큰 Green을 주장하는 경우다.
- 착각 방지
- phase 이름·manifest finalState·history hash·exit0 하나를 W25 증거 전체와 같다고 보지 않는다.
- 하지 않는 일
- Review는 Git commit·audio·설명 의미를 자동 검증하지 않는다; hash는 XML bytes·사람 설명을 대신하지 않는다; reference와 learner root는 서로 달라야 한다; 기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다; 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
- 다음 연결
- 다음 조각 또는 F19 evidence 판정으로 상태를 넘긴다.
실행 순서 — D7 Review — 기존 CumulativeGreen을 reviewedPhase로 연결
-
reviewedPhase=CumulativeGreen가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 새 Gradle/XML을 만들지 않고 prior CumulativeGreen·leak 경계·history 증가를 확인하며 phase는 CumulativeGreen으로 유지한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘hash는 XML bytes·사람 설명을 대신하지 않는다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 reviewedPhase=CumulativeGreen와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 08 / 13
실제 값 따라가기
같은 입력값이 어느 줄을 지나 어떤 결과가 되는지 추적합니다.
| 순서 | 들어온 값 | 코드가 하는 일 | 나온 값·상태 | 경계 |
|---|---|---|---|---|
| 입력 | Review requires CumulativeGreen | source 계약에 대입 | F19 실행/설명 시작 상태 | Review는 Git commit·audio·설명 의미를 자동 검증하지 않는다 |
| 검증 | reviewedPhase=CumulativeGreen | expected와 actual 또는 형식 대조 | 통과 또는 첫 mismatch | hash는 XML bytes·사람 설명을 대신하지 않는다 |
| 증거 | runtime_claim=false | marker·hash·row를 같은 run에 연결 | 범위가 적힌 evidence 후보 | 이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다 |
실제 값 — D7 Review — 기존 CumulativeGreen을 reviewedPhase로 연결
-
phase remains CumulativeGreen가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 새 Gradle/XML을 만들지 않고 prior CumulativeGreen·leak 경계·history 증가를 확인하며 phase는 CumulativeGreen으로 유지한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘reference와 learner root는 서로 달라야 한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 phase remains CumulativeGreen와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 09 / 13
Gradle·JUnit XML·PowerShell·SQL 내부에서 벌어지는 일
세 test phase, XML bytes archive, Review, 별도 Q41, USER_ATTESTED sealed 결과의 owner와 증명 범위를 구분합니다.
W25-D7-review.ps1 bytes와 track·phase·hash 계약을 읽는다.
SECURITIES 기본 선택과 파일 존재·phase 이름만으로 runtime Green을 주장할 수 없다. 실제 selected-track evidence와 실행 결과는 별도다.RecordRed·RecordGreen·Cumulative에서만 native exit와 exact JUnit XML을 만든다.
Review는 Git commit·audio·설명 의미를 자동 검증하지 않는다XML bytes를 고유 파일로 보존하고 history hash와 묶은 뒤, Review는 기존 CumulativeGreen만 인용한다. Q41은 별도 PostgreSQL evidence, sealed official status는 user-attested evidence로 남긴다.
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다첫 실패 경계 — D7 Review — 기존 CumulativeGreen을 reviewedPhase로 연결
-
no new execution가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 새 Gradle/XML을 만들지 않고 prior CumulativeGreen·leak 경계·history 증가를 확인하며 phase는 CumulativeGreen으로 유지한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 no new execution와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 10 / 13
흔한 착각과 틀린 예
그럴듯하지만 틀린 해석을 반례로 고칩니다.
❌ Prepare·VerifyStarter·VerifySolution·Review도 Gradle을 실행해 Green을 만든다.
왜 틀리나 runtime에서 test 실행을 소유하는 phase는 RecordRed·RecordGreen·Cumulative뿐이다.
바르게 읽기 각 phase history의 execution 유무와 mode를 직접 확인한다.
반례 VerifySolution은 solution hash만 검증하므로 새 JUnit XML이 없어야 정상이다.
❌ 기본 트랙이 SECURITIES이므로 CARD도 함께 실행해도 되고, 기본 배지만으로 runtime 선택·실행 증거가 완성된다.
왜 틀리나 W25 계약은 실제 사용자 근거가 있는 선택 트랙 하나와 반대 트랙 leak 부재를 요구한다.
바르게 읽기 기본 선택은 SECURITIES(증권)이며 명시적 CARD 선택은 덮어쓰기다. 실행 전 최종 선택 한 개를 selected-track.csv·근거·state에 같은 값으로 고정한다.
반례 SECURITIES 기본 배지만 보고 test 실행을 주장하거나 두 트랙 test가 함께 보이면 선택 경계를 위반한다.
❌ progressive_contract Green이면 manifest의 finalState 10_000도 증명된다.
왜 틀리나 packaged test는 1_000에서 300을 처리한 700/300만 assert한다.
바르게 읽기 10_000 finalState는 별도 learner test 또는 사람이 결박한 evidence로 증명한다.
반례 runtime은 domainContract.finalState 문자열을 parse하거나 assert하지 않는다.
❌ history에 XML SHA가 있으니 Red·Green·Cumulative XML 원본이 모두 보존됐다.
왜 틀리나 다음 cleanTest가 build/test-results의 이전 XML을 덮어쓰며 state는 bytes를 복사하지 않는다.
바르게 읽기 각 phase 직후 고유 evidence 경로로 원자 복사하고 hash를 history와 대조한다.
반례 RecordGreen 뒤에는 Red XML 경로가 사라질 수 있다.
❌ Review가 새 test를 실행해 CumulativeGreen을 다시 만들고 Q41·sealed official 결과까지 자동 확인한다.
왜 틀리나 Review는 기존 CumulativeGreen을 전제로 review entry와 leak check만 기록한다. Q41은 별도 PostgreSQL 과제이고 sealed official status는 user-attested다.
바르게 읽기 Review에서는 reviewedPhase와 history 증가만 보고, Q41 native evidence와 USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED sealed evidence를 별도로 판정한다.
반례 Review 뒤 phase는 여전히 CumulativeGreen이고 새 execution/XML·Q41 transcript·official login verification이 생기지 않는다.
STEP 11 / 13
이 코드가 보장하지 않는 것
선택 미결정·10_000 finalState·XML 보존·Review/Q41/sealed official truth처럼 이 코드가 책임지지 않는 일을 분리합니다.
Review는 Git commit·audio·설명 의미를 자동 검증하지 않는다
이 책임을 맡는 곳: runtime Gatehash는 XML bytes·사람 설명을 대신하지 않는다
이 책임을 맡는 곳: external/human reviewreference와 learner root는 서로 달라야 한다
이 책임을 맡는 곳: release manifest기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
이 책임을 맡는 곳: 운영 환경증명하지 않는 범위 — D7 Review — 기존 CumulativeGreen을 reviewedPhase로 연결
-
runtime_claim=false가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?
-
순서는 source를 읽고 입력을 고정한 뒤 새 Gradle/XML을 만들지 않고 prior CumulativeGreen·leak 경계·history 증가를 확인하며 phase는 CumulativeGreen으로 유지한다. 마지막에 실제 marker와 evidence를 대조하는 거야.
-
여기서 멈출 경계는 ‘이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.
-
판정은 runtime_claim=false와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.
STEP 12 / 13
직접 다시 써보기
뜻 → 조각 → 전체 코드 순서로 다시 씁니다.
1단계 · 뜻부터 복원
- 새 Gradle/XML을 만들지 않고 prior CumulativeGreen·leak 경계·history 증가를 확인하며 phase는 CumulativeGreen으로 유지한다.
- 핵심 값은 Review requires CumulativeGreen, reviewedPhase=CumulativeGreen, phase remains CumulativeGreen, no new execution, runtime_claim=false다.
2단계 · 코드 조각 재조립
- 1. 기존 CumulativeGreen을 전제로 review entry와 leak 경계만 다시 기록한다
- 2. W25부터 현재 주까지 선택 트랙 selector를 누적 실행하는 phase다
- 3. PowerShell 오류를 계속 진행하지 않고 중단시키는 기본 정책을 둔다
- 4. 입력 경로를 실제 절대 경로로 확인한다
- 5. 입력 경로를 실제 절대 경로로 확인한다
- 6. 조건·반복·함수의 실행 block을 연다
- 7. 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다
- 8. 앞에서 연 block 또는 호출 범위를 닫는다
3단계 · 파일 전체 다시 쓰기
illustrative/powershell/W25-D7-review.ps1을 새 파일에 다시 쓰고 expected·actual·실패·cleanup·비범위를 주석으로 표시한다.
자가 점검
- 비어 있지 않은 모든 source 줄을 한 번씩 읽었나?
- 기본 트랙을 SECURITIES(증권) 하나로 두고 기본 선택·selected-track evidence·runtime Green을 서로 분리했나?
- Review·Q41·USER_ATTESTED sealed 상태를 자동 성공으로 꾸미지 않았나?
- XML bytes archive와 첫 실패·cleanup 책임을 설명할 수 있나?
STEP 13 / 13
전체 원본 source
감사로 고정한 전체 source를 가감 없이 확인합니다.
학습용 예시 전체 확인하기 · 정본 답안 아님 · NOT_RUN
# W25 PDF p48-p52의 Review 흐름을 정리한 학습용 예시다.
# Review는 새 Gradle/XML을 읽지 않고 기존 CumulativeGreen history와 leak 경계를 다시 확인한다.
$ErrorActionPreference = 'Stop'
$ReferenceRoot = (Resolve-Path -LiteralPath $env:FINANCIAL_IT_REFERENCE_ROOT).Path
$LearnerRoot = (Resolve-Path -LiteralPath $env:FINANCIAL_IT_LEARNER_ROOT).Path
if ([string]::Equals($ReferenceRoot, $LearnerRoot, [StringComparison]::OrdinalIgnoreCase)) {
throw 'reference and learner roots must be different'
}
$StatePath = Join-Path $LearnerRoot '.track-learning-stage.json'
$Before = Get-Content -Raw -LiteralPath $StatePath | ConvertFrom-Json
if ($Before.week -ne 25 -or $Before.phase -cne 'CumulativeGreen') { throw 'Review requires CumulativeGreen' }
$Runner = Join-Path $ReferenceRoot 'scripts\apply-track-learning-stage.ps1'
& powershell.exe -NoProfile -ExecutionPolicy Bypass -File $Runner `
-ReferenceRoot $ReferenceRoot -LearnerRoot $LearnerRoot -Week 25 -Phase Review -TimeoutSeconds 1200
if ($LASTEXITCODE -ne 0) { throw "W25 Review native exit=$LASTEXITCODE" }
$After = Get-Content -Raw -LiteralPath $StatePath | ConvertFrom-Json
$Entry = @($After.history)[-1]
if ($After.phase -cne 'CumulativeGreen' -or $Entry.phase -cne 'Review') { throw 'Review state mismatch' }
if ($Entry.reviewedPhase -cne 'CumulativeGreen' -or $null -ne $Entry.execution) {
throw 'Review must bind prior CumulativeGreen without creating new execution evidence'
}
$Hash = (Get-FileHash -LiteralPath $StatePath -Algorithm SHA256).Hash.ToLowerInvariant()
"W25_REVIEW_RECORDED track=$($After.track) phase=CumulativeGreen runtime_claim=false state_sha256=$Hash"