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입니다.

패키지 정본 보조 계약 · exact PowerShell bytes 2개패키지 정본 보조 계약 · exact W25 manifest bytes 2개패키지 정본 보조 계약 · exact JUnit test bytes 2개PDF 전문 정본 · learner starter Java 2개PDF 전문 정본 · learner solution Java 2개학습용 예시 · W25 phase wrapper · 정본 답안 아님 · 로컬 미실행 8개학습용 예시 · W25-SQL-Q41 prompt 기반 · 정본 답안 아님 · workbook 제공 정답 아님 1개기본 트랙 SECURITIES · 증권실행 상태 NOT_RUN항목마다 13단계연결 700줄번역 700줄원문 PDF 2–55쪽
01

apply-track-learning-stage.ps1 — 7단계의 단일 진입점

scripts/apply-track-learning-stage.ps1

패키지 정본 보조 계약 · exact PowerShell bytes · 정본 · W25-F01
28줄 연결28줄 번역3 chunks
01

STEP 01 / 13

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

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

오늘의 한 문장

서로 다른 reference/learner root와 W25 phase를 fail-closed Python runtime에 전달한다.

  1. Week=25은 어느 source와 실제 결과에서 확인해야 할까?
  2. 첫 실패를 만드는 조건과 fail-closed 지점은 어디일까?
  3. 왜 ‘reference와 learner root는 서로 달라야 한다’를 별도 경계로 남겨야 할까?
이 파일에서 끝까지 다시 쓰는 값Week=25Prepare→ReviewTimeoutSeconds=1200distinct rootsnative exit
왜 필요한가 — apply-track-learning-stage.ps1 — 7단계의 단일 진입점히토리 → 니지카 → 료 → 키타
  1. 히토리

    Week=25가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 서로 다른 reference/learner root와 W25 phase를 fail-closed Python runtime에 전달한다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘reference와 learner root는 서로 달라야 한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 Week=25와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

02

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 확인을 대신하지 않는다.

03

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는 서로 달라야 한다
04

STEP 04 / 13

비유 ↔ 코드 전체 연결표

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

단어 몇 개만 뽑은 표가 아닙니다.패키지 정본 보조 계약 · exact PowerShell bytes에서 비어 있지 않은 모든 줄을 원본 줄 번호 그대로 연결했습니다.28 / 28 연결
정확한 원본 줄STARRY 비유실제 뜻·입력·결과·한계
1줄F01-L01 param( 출고표 1번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 PowerShell script가 받을 입력 계약을 연다.
입력
이전 줄의 상태와 Week=25
결과·효과
관찰 상태 F01-001가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
2줄F01-L02 [Parameter(Mandatory=$true)][string]$ReferenceRoot, 출고표 2번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 이 인자가 빠지면 실행 시작 전에 binding을 거절한다.
입력
$true, $ReferenceRoot
결과·효과
관찰 상태 F01-002가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
3줄F01-L03 [Parameter(Mandatory=$true)][string]$LearnerRoot, 출고표 3번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 이 인자가 빠지면 실행 시작 전에 binding을 거절한다.
입력
$true, $LearnerRoot
결과·효과
관찰 상태 F01-003가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
4줄F01-L04 [Parameter(Mandatory=$true)][ValidateRange(25,38)][int]$Week, 출고표 4번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 이 인자가 빠지면 실행 시작 전에 binding을 거절한다.
입력
$true, 25, 38
결과·효과
관찰 상태 F01-004가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
wrapper 자체는 manifest나 JUnit XML을 판정하지 않는다
5줄F01-L05 [Parameter(Mandatory=$true)] 출고표 5번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 이 인자가 빠지면 실행 시작 전에 binding을 거절한다.
입력
$true
결과·효과
관찰 상태 F01-005가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
6줄F01-L06 [ValidateSet('Prepare','VerifyStarter','RecordRed','VerifySolution','RecordGreen','Cumulative','Review')] 출고표 6번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 starter canonical/raw hash만 검증하고 Gradle은 실행하지 않는 phase다.
입력
'Prepare', 'VerifyStarter', 'RecordRed'
결과·효과
관찰 상태 F01-006가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
7줄F01-L07 [string]$Phase, 출고표 7번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 apply-track-learning-stage.ps1의 다음 검증 또는 설명 단계를 구성한다.
입력
$Phase
결과·효과
관찰 상태 F01-007가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
8줄F01-L08 [ValidateRange(1,7200)][int]$TimeoutSeconds=1200, 출고표 8번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 apply-track-learning-stage.ps1의 다음 검증 또는 설명 단계를 구성한다.
입력
1, 7200, $TimeoutSeconds
결과·효과
관찰 상태 F01-008가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
wrapper 자체는 manifest나 JUnit XML을 판정하지 않는다
9줄F01-L09 [string]$Python='' 출고표 9번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 apply-track-learning-stage.ps1의 다음 검증 또는 설명 단계를 구성한다.
입력
$Python
결과·효과
관찰 상태 F01-009가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
10줄F01-L10 ) 출고표 10번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
입력
이전 줄의 상태와 Week=25
결과·효과
관찰 상태 F01-010가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
11줄F01-L11 $ErrorActionPreference='Stop' 출고표 11번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 PowerShell 오류를 계속 진행하지 않고 중단시키는 기본 정책을 둔다.
입력
$ErrorActionPreference, 'Stop'
결과·효과
관찰 상태 F01-011가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
12줄F01-L12 $reference=(Resolve-Path -LiteralPath $ReferenceRoot -ErrorAction Stop).Path 출고표 12번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 입력 경로를 실제 절대 경로로 확인한다.
입력
$reference, $ReferenceRoot
결과·효과
관찰 상태 F01-012가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
wrapper 자체는 manifest나 JUnit XML을 판정하지 않는다
13줄F01-L13 $learner=(Resolve-Path -LiteralPath $LearnerRoot -ErrorAction Stop).Path 출고표 13번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 입력 경로를 실제 절대 경로로 확인한다.
입력
$learner, $LearnerRoot
결과·효과
관찰 상태 F01-013가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
14줄F01-L14 if([string]::Equals($reference,$learner,[StringComparison]::OrdinalIgnoreCase)){ 출고표 14번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 조건·반복·함수의 실행 block을 연다.
입력
$reference, $learner
결과·효과
관찰 상태 F01-014가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
15줄F01-L15 throw 'ReferenceRoot and LearnerRoot must be different directories' 출고표 15번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
입력
이전 줄의 상태와 Week=25
결과·효과
관찰 상태 F01-015가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
16줄F01-L16 } 출고표 16번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
입력
이전 줄의 상태와 Week=25
결과·효과
관찰 상태 F01-016가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
wrapper 자체는 manifest나 JUnit XML을 판정하지 않는다
17줄F01-L17 $tool=Join-Path $reference 'scripts/track_progressive_runtime.py' 출고표 17번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
입력
$tool, $reference, 'scripts/track_progressive_runtime.py'
결과·효과
관찰 상태 F01-017가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
18줄F01-L18 if(!(Test-Path -LiteralPath $tool -PathType Leaf)){throw "runtime missing: $tool"} 출고표 18번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 필수 파일이나 경로가 실제로 있는지 확인한다.
입력
$tool, "runtime missing: $tool"
결과·효과
관찰 상태 F01-018가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
19줄F01-L19 if([string]::IsNullOrWhiteSpace($Python)){ 출고표 19번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 조건·반복·함수의 실행 block을 연다.
입력
$Python
결과·효과
관찰 상태 F01-019가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
20줄F01-L20 $py=Get-Command py -ErrorAction SilentlyContinue 출고표 20번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
입력
$py
결과·효과
관찰 상태 F01-020가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
wrapper 자체는 manifest나 JUnit XML을 판정하지 않는다
21줄F01-L21 if($null-ne$py){$command=$py.Source;$prefix=@('-3')} 출고표 21번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 apply-track-learning-stage.ps1의 다음 검증 또는 설명 단계를 구성한다.
입력
$null, $py, $command
결과·효과
관찰 상태 F01-021가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
22줄F01-L22 else{ 출고표 22번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 조건·반복·함수의 실행 block을 연다.
입력
이전 줄의 상태와 Week=25
결과·효과
관찰 상태 F01-022가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
23줄F01-L23 $pythonCommand=Get-Command python -ErrorAction Stop 출고표 23번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
입력
$pythonCommand
결과·효과
관찰 상태 F01-023가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
24줄F01-L24 $command=$pythonCommand.Source;$prefix=@() 출고표 24번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
입력
$command, $pythonCommand, $prefix
결과·효과
관찰 상태 F01-024가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
wrapper 자체는 manifest나 JUnit XML을 판정하지 않는다
25줄F01-L25 } 출고표 25번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
입력
이전 줄의 상태와 Week=25
결과·효과
관찰 상태 F01-025가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
26줄F01-L26 }else{$command=$Python;$prefix=@()} 출고표 26번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 apply-track-learning-stage.ps1의 다음 검증 또는 설명 단계를 구성한다.
입력
$command, $Python, $prefix
결과·효과
관찰 상태 F01-026가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
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의 다음 검증 또는 설명 단계를 구성한다.
입력
$command, $tool, $reference
결과·효과
관찰 상태 F01-027가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
28줄F01-L28 if($LASTEXITCODE-ne 0){throw "track stage failed: W${Week} phase=$Phase exit=$LASTEXITCODE"} 출고표 28번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 native process 종료 코드를 검사해 실패를 놓치지 않는다.
입력
$LASTEXITCODE, 0, $Phase
결과·효과
관찰 상태 F01-028가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
wrapper 자체는 manifest나 JUnit XML을 판정하지 않는다
05

STEP 05 / 13

원본 코드 조각

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

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

F01-C01 · 원문 1–12줄1–12줄
1–12줄 원본
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
F01-C02 · 원문 13–24줄13–24줄
13–24줄 원본
$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=@()
F01-C03 · 원문 25–28줄25–28줄
25–28줄 원본
  }
}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"}
06

STEP 06 / 13

코드 한 줄씩 한국어로 번역

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

전체 번역 28 / 28

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

원본한국어 번역
1param(실행 의미: 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실행 의미: 입력 경로를 실제 절대 경로로 확인한다.
14if([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 변수에 저장한다.
18if(!(Test-Path -LiteralPath $tool -PathType Leaf)){throw "runtime missing: $tool"}실행 의미: 필수 파일이나 경로가 실제로 있는지 확인한다.
19if([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의 다음 검증 또는 설명 단계를 구성한다.
28if($LASTEXITCODE-ne 0){throw "track stage failed: W${Week} phase=$Phase exit=$LASTEXITCODE"}실행 의미: native process 종료 코드를 검사해 실패를 놓치지 않는다.
07

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를 서로 대체하지 않는다.

실행 순서

  1. 기본 트랙은 SECURITIES(증권)이며, 명시적 CARD 선택은 기본값을 덮어쓴다. 실제 실행 전 최종 선택 한 개를 selected-track.csv·근거·state에 같은 값으로 기록하고 서로 다른 reference/learner root를 확인한다.
  2. Prepare→VerifyStarter→RecordRed→VerifySolution→RecordGreen→Cumulative→Review 순서를 지킨다.
  3. test를 소유한 세 phase에서만 native exit와 exact JUnit XML 수치를 판정한다.
  4. 다음 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단계의 단일 진입점히토리 → 니지카 → 료 → 키타
  1. 히토리

    Prepare→Review가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 서로 다른 reference/learner root와 W25 phase를 fail-closed Python runtime에 전달한다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 Prepare→Review와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

08

STEP 08 / 13

실제 값 따라가기

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

순서들어온 값코드가 하는 일나온 값·상태경계
입력Week=25source 계약에 대입F01 실행/설명 시작 상태reference와 learner root는 서로 달라야 한다
검증Prepare→Reviewexpected와 actual 또는 형식 대조통과 또는 첫 mismatch기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
증거native exitmarker·hash·row를 같은 run에 연결범위가 적힌 evidence 후보wrapper 자체는 manifest나 JUnit XML을 판정하지 않는다
실제 값 — apply-track-learning-stage.ps1 — 7단계의 단일 진입점히토리 → 니지카 → 료 → 키타
  1. 히토리

    TimeoutSeconds=1200가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 서로 다른 reference/learner root와 W25 phase를 fail-closed Python runtime에 전달한다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 TimeoutSeconds=1200와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

09

STEP 09 / 13

Gradle·JUnit XML·PowerShell·SQL 내부에서 벌어지는 일

세 test phase, XML bytes archive, Review, 별도 Q41, USER_ATTESTED sealed 결과의 owner와 증명 범위를 구분합니다.

source/contract

apply-track-learning-stage.ps1 bytes와 track·phase·hash 계약을 읽는다.

SECURITIES 기본 선택과 파일 존재·phase 이름만으로 runtime Green을 주장할 수 없다. 실제 selected-track evidence와 실행 결과는 별도다.
execution/evidence

RecordRed·RecordGreen·Cumulative에서만 native exit와 exact JUnit XML을 만든다.

reference와 learner root는 서로 달라야 한다
retention/review

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단계의 단일 진입점히토리 → 니지카 → 료 → 키타
  1. 히토리

    distinct roots가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 서로 다른 reference/learner root와 W25 phase를 fail-closed Python runtime에 전달한다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘wrapper 자체는 manifest나 JUnit XML을 판정하지 않는다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 distinct roots와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

10

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이 생기지 않는다.

11

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 manifest
증명 범위

wrapper 자체는 manifest나 JUnit XML을 판정하지 않는다

이 책임을 맡는 곳: 운영 환경
증명하지 않는 범위 — apply-track-learning-stage.ps1 — 7단계의 단일 진입점히토리 → 니지카 → 료 → 키타
  1. 히토리

    native exit가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 서로 다른 reference/learner root와 W25 phase를 fail-closed Python runtime에 전달한다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘reference와 learner root는 서로 달라야 한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 native exit와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

12

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. 1. PowerShell script가 받을 입력 계약을 연다
  2. 2. 이 인자가 빠지면 실행 시작 전에 binding을 거절한다
  3. 3. 이 인자가 빠지면 실행 시작 전에 binding을 거절한다
  4. 4. 이 인자가 빠지면 실행 시작 전에 binding을 거절한다
  5. 5. 이 인자가 빠지면 실행 시작 전에 binding을 거절한다
  6. 6. starter canonical/raw hash만 검증하고 Gradle은 실행하지 않는 phase다
  7. 7. apply-track-learning-stage.ps1의 다음 검증 또는 설명 단계를 구성한다
  8. 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 책임을 설명할 수 있나?
13

STEP 13 / 13

전체 원본 source

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

원문 정본 전체 source 확인하기
패키지 정본 보조 계약 · exact PowerShell bytesscripts/apply-track-learning-stage.ps1SHA-256 4d2b41bd4367d135719d53d4f14b6c1b5364d71028526514c1503a426aa4b942
apply-track-learning-stage.ps1 — 7단계의 단일 진입점 전체
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"}
02

verify-track-learner-proof.ps1 — test 실행 phase만 허용하는 보조 forwarder

scripts/verify-track-learner-proof.ps1

패키지 정본 보조 계약 · exact PowerShell bytes · 정본 · W25-F02
13줄 연결13줄 번역2 chunks
01

STEP 01 / 13

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

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

오늘의 한 문장

RecordRed·RecordGreen·Cumulative만 apply wrapper에 전달해 native proof 실패를 PowerShell 실패로 올린다.

  1. RecordRed은 어느 source와 실제 결과에서 확인해야 할까?
  2. 첫 실패를 만드는 조건과 fail-closed 지점은 어디일까?
  3. 왜 ‘reference와 learner root는 서로 달라야 한다’를 별도 경계로 남겨야 할까?
이 파일에서 끝까지 다시 쓰는 값RecordRedRecordGreenCumulativenative exitWeek=25
왜 필요한가 — verify-track-learner-proof.ps1 — test 실행 phase만 허용하는 보조 forwarder히토리 → 니지카 → 료 → 키타
  1. 히토리

    RecordRed가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 RecordRed·RecordGreen·Cumulative만 apply wrapper에 전달해 native proof 실패를 PowerShell 실패로 올린다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘reference와 learner root는 서로 달라야 한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 RecordRed와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

02

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 확인을 대신하지 않는다.

03

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는 서로 달라야 한다
04

STEP 04 / 13

비유 ↔ 코드 전체 연결표

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

단어 몇 개만 뽑은 표가 아닙니다.패키지 정본 보조 계약 · exact PowerShell bytes에서 비어 있지 않은 모든 줄을 원본 줄 번호 그대로 연결했습니다.13 / 13 연결
정확한 원본 줄STARRY 비유실제 뜻·입력·결과·한계
1줄F02-L01 param( 출고표 1번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 PowerShell script가 받을 입력 계약을 연다.
입력
이전 줄의 상태와 RecordRed
결과·효과
관찰 상태 F02-001가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
2줄F02-L02 [Parameter(Mandatory=$true)][string]$ReferenceRoot, 출고표 2번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 이 인자가 빠지면 실행 시작 전에 binding을 거절한다.
입력
$true, $ReferenceRoot
결과·효과
관찰 상태 F02-002가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
3줄F02-L03 [Parameter(Mandatory=$true)][string]$LearnerRoot, 출고표 3번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 이 인자가 빠지면 실행 시작 전에 binding을 거절한다.
입력
$true, $LearnerRoot
결과·효과
관찰 상태 F02-003가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
4줄F02-L04 [Parameter(Mandatory=$true)][ValidateRange(25,38)][int]$Week, 출고표 4번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 이 인자가 빠지면 실행 시작 전에 binding을 거절한다.
입력
$true, 25, 38
결과·효과
관찰 상태 F02-004가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
W25 PDF의 공식 진입점은 apply-track-learning-stage.ps1이다
5줄F02-L05 [Parameter(Mandatory=$true)][ValidateSet('RecordRed','RecordGreen','Cumulative')][string]$Phase, 출고표 5번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 선택 트랙 test 하나의 의도한 실패와 Red marker를 기록하는 phase다.
입력
$true, 'RecordRed', 'RecordGreen'
결과·효과
관찰 상태 F02-005가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
6줄F02-L06 [ValidateRange(1,7200)][int]$TimeoutSeconds=1200, 출고표 6번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 verify-track-learner-proof.ps1의 다음 검증 또는 설명 단계를 구성한다.
입력
1, 7200, $TimeoutSeconds
결과·효과
관찰 상태 F02-006가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
7줄F02-L07 [string]$Python='' 출고표 7번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 verify-track-learner-proof.ps1의 다음 검증 또는 설명 단계를 구성한다.
입력
$Python
결과·효과
관찰 상태 F02-007가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
8줄F02-L08 ) 출고표 8번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
입력
이전 줄의 상태와 RecordRed
결과·효과
관찰 상태 F02-008가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
W25 PDF의 공식 진입점은 apply-track-learning-stage.ps1이다
9줄F02-L09 $ErrorActionPreference='Stop' 출고표 9번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 PowerShell 오류를 계속 진행하지 않고 중단시키는 기본 정책을 둔다.
입력
$ErrorActionPreference, 'Stop'
결과·효과
관찰 상태 F02-009가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
10줄F02-L10 $runner=Join-Path (Resolve-Path -LiteralPath $ReferenceRoot).Path 'scripts/apply-track-learning-stage.ps1' 출고표 10번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 입력 경로를 실제 절대 경로로 확인한다.
입력
$runner, $ReferenceRoot, 'scripts/apply-track-learning-stage.ps1'
결과·효과
관찰 상태 F02-010가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
11줄F02-L11 & powershell.exe -NoProfile -ExecutionPolicy Bypass -File $runner ` 출고표 11번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 verify-track-learner-proof.ps1의 다음 검증 또는 설명 단계를 구성한다.
입력
$runner
결과·효과
관찰 상태 F02-011가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
12줄F02-L12 -ReferenceRoot $ReferenceRoot -LearnerRoot $LearnerRoot -Week $Week -Phase $Phase -TimeoutSeconds $TimeoutSeconds -Python $Python 출고표 12번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 verify-track-learner-proof.ps1의 다음 검증 또는 설명 단계를 구성한다.
입력
$ReferenceRoot, $LearnerRoot, $Week
결과·효과
관찰 상태 F02-012가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
W25 PDF의 공식 진입점은 apply-track-learning-stage.ps1이다
13줄F02-L13 if($LASTEXITCODE-ne 0){throw "native track proof failed: W${Week} phase=$Phase exit=$LASTEXITCODE"} 출고표 13번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 native process 종료 코드를 검사해 실패를 놓치지 않는다.
입력
$LASTEXITCODE, 0, $Phase
결과·효과
관찰 상태 F02-013가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
05

STEP 05 / 13

원본 코드 조각

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

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

F02-C01 · 원문 1–12줄1–12줄
1–12줄 원본
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
F02-C02 · 원문 13–13줄13–13줄
13–13줄 원본
if($LASTEXITCODE-ne 0){throw "native track proof failed: W${Week} phase=$Phase exit=$LASTEXITCODE"}
06

STEP 06 / 13

코드 한 줄씩 한국어로 번역

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

전체 번역 13 / 13

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

원본한국어 번역
1param(실행 의미: 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의 다음 검증 또는 설명 단계를 구성한다.
13if($LASTEXITCODE-ne 0){throw "native track proof failed: W${Week} phase=$Phase exit=$LASTEXITCODE"}실행 의미: native process 종료 코드를 검사해 실패를 놓치지 않는다.
07

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를 서로 대체하지 않는다.

실행 순서

  1. 기본 트랙은 SECURITIES(증권)이며, 명시적 CARD 선택은 기본값을 덮어쓴다. 실제 실행 전 최종 선택 한 개를 selected-track.csv·근거·state에 같은 값으로 기록하고 서로 다른 reference/learner root를 확인한다.
  2. Prepare→VerifyStarter→RecordRed→VerifySolution→RecordGreen→Cumulative→Review 순서를 지킨다.
  3. test를 소유한 세 phase에서만 native exit와 exact JUnit XML 수치를 판정한다.
  4. 다음 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히토리 → 니지카 → 료 → 키타
  1. 히토리

    RecordGreen가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 RecordRed·RecordGreen·Cumulative만 apply wrapper에 전달해 native proof 실패를 PowerShell 실패로 올린다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 RecordGreen와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

08

STEP 08 / 13

실제 값 따라가기

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

순서들어온 값코드가 하는 일나온 값·상태경계
입력RecordRedsource 계약에 대입F02 실행/설명 시작 상태reference와 learner root는 서로 달라야 한다
검증RecordGreenexpected와 actual 또는 형식 대조통과 또는 첫 mismatch기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
증거Week=25marker·hash·row를 같은 run에 연결범위가 적힌 evidence 후보W25 PDF의 공식 진입점은 apply-track-learning-stage.ps1이다
실제 값 — verify-track-learner-proof.ps1 — test 실행 phase만 허용하는 보조 forwarder히토리 → 니지카 → 료 → 키타
  1. 히토리

    Cumulative가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 RecordRed·RecordGreen·Cumulative만 apply wrapper에 전달해 native proof 실패를 PowerShell 실패로 올린다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 Cumulative와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

09

STEP 09 / 13

Gradle·JUnit XML·PowerShell·SQL 내부에서 벌어지는 일

세 test phase, XML bytes archive, Review, 별도 Q41, USER_ATTESTED sealed 결과의 owner와 증명 범위를 구분합니다.

source/contract

verify-track-learner-proof.ps1 bytes와 track·phase·hash 계약을 읽는다.

SECURITIES 기본 선택과 파일 존재·phase 이름만으로 runtime Green을 주장할 수 없다. 실제 selected-track evidence와 실행 결과는 별도다.
execution/evidence

RecordRed·RecordGreen·Cumulative에서만 native exit와 exact JUnit XML을 만든다.

reference와 learner root는 서로 달라야 한다
retention/review

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히토리 → 니지카 → 료 → 키타
  1. 히토리

    native exit가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 RecordRed·RecordGreen·Cumulative만 apply wrapper에 전달해 native proof 실패를 PowerShell 실패로 올린다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘W25 PDF의 공식 진입점은 apply-track-learning-stage.ps1이다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 native exit와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

10

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이 생기지 않는다.

11

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 manifest
증명 범위

W25 PDF의 공식 진입점은 apply-track-learning-stage.ps1이다

이 책임을 맡는 곳: 운영 환경
증명하지 않는 범위 — verify-track-learner-proof.ps1 — test 실행 phase만 허용하는 보조 forwarder히토리 → 니지카 → 료 → 키타
  1. 히토리

    Week=25가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 RecordRed·RecordGreen·Cumulative만 apply wrapper에 전달해 native proof 실패를 PowerShell 실패로 올린다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘reference와 learner root는 서로 달라야 한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 Week=25와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

12

STEP 12 / 13

직접 다시 써보기

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

1단계 · 뜻부터 복원

  • RecordRed·RecordGreen·Cumulative만 apply wrapper에 전달해 native proof 실패를 PowerShell 실패로 올린다.
  • 핵심 값은 RecordRed, RecordGreen, Cumulative, native exit, Week=25다.

2단계 · 코드 조각 재조립

  1. 1. PowerShell script가 받을 입력 계약을 연다
  2. 2. 이 인자가 빠지면 실행 시작 전에 binding을 거절한다
  3. 3. 이 인자가 빠지면 실행 시작 전에 binding을 거절한다
  4. 4. 이 인자가 빠지면 실행 시작 전에 binding을 거절한다
  5. 5. 선택 트랙 test 하나의 의도한 실패와 Red marker를 기록하는 phase다
  6. 6. verify-track-learner-proof.ps1의 다음 검증 또는 설명 단계를 구성한다
  7. 7. verify-track-learner-proof.ps1의 다음 검증 또는 설명 단계를 구성한다
  8. 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 책임을 설명할 수 있나?
13

STEP 13 / 13

전체 원본 source

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

원문 정본 전체 source 확인하기
패키지 정본 보조 계약 · exact PowerShell bytesscripts/verify-track-learner-proof.ps1SHA-256 07545a4b6caa00c610abf2e29f79cb217c4c5c6a9c74edc924f800d11e93c361
verify-track-learner-proof.ps1 — test 실행 phase만 허용하는 보조 forwarder 전체
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"}
03

SECURITIES manifest — 현금 available+reserved 불변식

track_learning_stages/securities/w25/manifest.json

패키지 정본 보조 계약 · exact W25 manifest bytes · 정본 · W25-F03
43줄 연결43줄 번역4 chunks
01

STEP 01 / 13

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

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

오늘의 한 문장

선택 트랙 selector·redMarker·starter/solution hash와 0/10_000 설명 계약을 고정한다.

  1. SECURITIES은 어느 source와 실제 결과에서 확인해야 할까?
  2. 첫 실패를 만드는 조건과 fail-closed 지점은 어디일까?
  3. 왜 ‘manifest 문자열은 실행 결과가 아니다’를 별도 경계로 남겨야 할까?
이 파일에서 끝까지 다시 쓰는 값SECURITIESprogressive_contractW25_SECURITIES_RED_EXPECTEDavailable=0,reserved=10_000LEARNER_AUTHORED
왜 필요한가 — SECURITIES manifest — 현금 available+reserved 불변식히토리 → 니지카 → 료 → 키타
  1. 히토리

    SECURITIES가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 선택 트랙 selector·redMarker·starter/solution hash와 0/10_000 설명 계약을 고정한다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘manifest 문자열은 실행 결과가 아니다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 SECURITIES와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

02

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 확인을 대신하지 않는다.

03

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이며 실제 실행은 정확히 한 트랙에만 귀속한다
04

STEP 04 / 13

비유 ↔ 코드 전체 연결표

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

단어 몇 개만 뽑은 표가 아닙니다.패키지 정본 보조 계약 · exact W25 manifest bytes에서 비어 있지 않은 모든 줄을 원본 줄 번호 그대로 연결했습니다.43 / 43 연결
정확한 원본 줄STARRY 비유실제 뜻·입력·결과·한계
1줄F03-L01 { 출고표 1번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
입력
이전 줄의 상태와 SECURITIES
결과·효과
관찰 상태 F03-001가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
manifest 문자열은 실행 결과가 아니다
2줄F03-L02 "schemaVersion": 2, 출고표 2번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 manifest 형식 버전을 2로 고정한다.
입력
"schemaVersion", 2
결과·효과
관찰 상태 F03-002가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
packaged test는 1_000→700/300만 assert한다
3줄F03-L03 "week": 25, 출고표 3번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 이 계약이 W25에만 적용됨을 숫자로 고정한다.
입력
"week", 25
결과·효과
관찰 상태 F03-003가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
finalState 10_000은 별도 evidence가 필요하다
4줄F03-L04 "track": "SECURITIES", 출고표 4번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 이 manifest의 SECURITIES 또는 CARD 분기 identity를 고정할 뿐 실제 사용자 선택을 대신하지 않는다.
입력
"track", "SECURITIES"
결과·효과
관찰 상태 F03-004가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
5줄F03-L05 "title": "현금 가용액·예약액 불변식", 출고표 5번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 manifest.json의 다음 검증 또는 설명 단계를 구성한다.
입력
"title", "현금 가용액·예약액 불변식"
결과·효과
관찰 상태 F03-005가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
6줄F03-L06 "claim": "reserve 뒤 available+reserved 보존", 출고표 6번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 manifest.json의 다음 검증 또는 설명 단계를 구성한다.
입력
"claim", "reserve 뒤 available+reserved 보존"
결과·효과
관찰 상태 F03-006가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
7줄F03-L07 "textEncoding": "UTF-8", 출고표 7번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 manifest.json의 다음 검증 또는 설명 단계를 구성한다.
입력
"textEncoding", "UTF-8"
결과·효과
관찰 상태 F03-007가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
manifest 문자열은 실행 결과가 아니다
8줄F03-L08 "newlinePolicy": "LF_CANONICAL_CRLF_EQUIVALENT", 출고표 8번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 manifest.json의 다음 검증 또는 설명 단계를 구성한다.
입력
"newlinePolicy", "LF_CANONICAL_CRLF_EQUIVALENT"
결과·효과
관찰 상태 F03-008가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
packaged test는 1_000→700/300만 assert한다
9줄F03-L09 "domainContract": { 출고표 9번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 불변식·실패 모드·최종 상태처럼 도메인 설명을 한 묶음으로 연다.
입력
"domainContract"
결과·효과
관찰 상태 F03-009가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
finalState 10_000은 별도 evidence가 필요하다
10줄F03-L10 "invariant": "예약 전후 availableCash+reservedCash 합계가 보존되고 두 값은 음수가 아니다.", 출고표 10번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 두 잔액의 합계 보존과 음수 금지라는 핵심 불변식을 설명한다.
입력
"invariant"
결과·효과
관찰 상태 F03-010가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
11줄F03-L11 "failureMode": "가용액 차감 누락으로 같은 현금을 중복 예약한다.", 출고표 11번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 차감 또는 증가 누락이 같은 돈·한도의 중복 사용으로 이어짐을 밝힌다.
입력
"failureMode", "가용액 차감 누락으로 같은 현금을 중복 예약한다."
결과·효과
관찰 상태 F03-011가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
12줄F03-L12 "implementationTarget": "src/main/java/com/example/financialcore/securities/CashWallet.java :: 현금 가용액·예약액 불변식 :: reserve 뒤 available+reserved 보존", 출고표 12번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 manifest.json의 다음 검증 또는 설명 단계를 구성한다.
입력
"implementationTarget"
결과·효과
관찰 상태 F03-012가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
13줄F03-L13 "finalState": "available=0, reserved=10_000", 출고표 13번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 PDF가 요구하는 10_000 시나리오를 설명용 계약에 고정하며 packaged 1_000→700/300 test의 자동 assertion과 분리한다.
입력
"finalState", "available=0, reserved=10_000"
결과·효과
관찰 상태 F03-013가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
manifest 문자열은 실행 결과가 아니다
14줄F03-L14 "recoveryFocus": "예약 전후 두 잔액과 합계를 먼저 비교한다.", 출고표 14번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 manifest.json의 다음 검증 또는 설명 단계를 구성한다.
입력
"recoveryFocus", "예약 전후 두 잔액과 합계를 먼저 비교한다."
결과·효과
관찰 상태 F03-014가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
packaged test는 1_000→700/300만 assert한다
15줄F03-L15 "interviewDefense": "현금 예약은 총액 보존과 음수 방지를 함께 증명해야 한다." 출고표 15번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 manifest.json의 다음 검증 또는 설명 단계를 구성한다.
입력
"interviewDefense", "현금 예약은 총액 보존과 음수 방지를 함께 증명해야 한다."
결과·효과
관찰 상태 F03-015가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
finalState 10_000은 별도 evidence가 필요하다
16줄F03-L16 }, 출고표 16번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 manifest.json의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 SECURITIES
결과·효과
관찰 상태 F03-016가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
17줄F03-L17 "selector": "com.example.financialcore.securities.W25CashWalletProgressiveTest", 출고표 17번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 선택 트랙의 정확한 JUnit suite 이름 하나를 지정한다.
입력
"selector"
결과·효과
관찰 상태 F03-017가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
18줄F03-L18 "testMethod": "progressive_contract", 출고표 18번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 progressive_contract 메서드 하나를 W25 proof 대상으로 지정한다.
입력
"testMethod", "progressive_contract"
결과·효과
관찰 상태 F03-018가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
19줄F03-L19 "redMarker": "W25_SECURITIES_RED_EXPECTED", 출고표 19번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 의도한 Red 실패를 다른 실패와 구분할 marker를 고정한다.
입력
"redMarker", "W25_SECURITIES_RED_EXPECTED"
결과·효과
관찰 상태 F03-019가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
manifest 문자열은 실행 결과가 아니다
20줄F03-L20 "predecessor": null, 출고표 20번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 manifest.json의 다음 검증 또는 설명 단계를 구성한다.
입력
"predecessor"
결과·효과
관찰 상태 F03-020가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
packaged test는 1_000→700/300만 assert한다
21줄F03-L21 "providedFiles": [], 출고표 21번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 manifest.json의 다음 검증 또는 설명 단계를 구성한다.
입력
"providedFiles"
결과·효과
관찰 상태 F03-021가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
finalState 10_000은 별도 evidence가 필요하다
22줄F03-L22 "testFiles": [ 출고표 22번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 manifest.json의 다음 검증 또는 설명 단계를 구성한다.
입력
"testFiles"
결과·효과
관찰 상태 F03-022가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
23줄F03-L23 { 출고표 23번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
입력
이전 줄의 상태와 SECURITIES
결과·효과
관찰 상태 F03-023가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
24줄F03-L24 "learnerPath": "src/test/java/com/example/financialcore/securities/W25CashWalletProgressiveTest.java", 출고표 24번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 manifest.json의 다음 검증 또는 설명 단계를 구성한다.
입력
"learnerPath"
결과·효과
관찰 상태 F03-024가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
25줄F03-L25 "asset": "tests/src/test/java/com/example/financialcore/securities/W25CashWalletProgressiveTest.java", 출고표 25번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 manifest.json의 다음 검증 또는 설명 단계를 구성한다.
입력
"asset"
결과·효과
관찰 상태 F03-025가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
manifest 문자열은 실행 결과가 아니다
26줄F03-L26 "introducedAt": 25, 출고표 26번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 manifest.json의 다음 검증 또는 설명 단계를 구성한다.
입력
"introducedAt", 25
결과·효과
관찰 상태 F03-026가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
packaged test는 1_000→700/300만 assert한다
27줄F03-L27 "ownership": "PROVIDED_FIXTURE_VERIFIED", 출고표 27번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 manifest.json의 다음 검증 또는 설명 단계를 구성한다.
입력
"ownership", "PROVIDED_FIXTURE_VERIFIED"
결과·효과
관찰 상태 F03-027가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
finalState 10_000은 별도 evidence가 필요하다
28줄F03-L28 "sha256": "f45516879819dc698533b48c434ee2c374a03d150bdd834fe39501db65532312", 출고표 28번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 현재 bytes를 64자리 digest로 evidence에 결박한다.
입력
"sha256"
결과·효과
관찰 상태 F03-028가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
29줄F03-L29 "canonicalTextSha256": "f45516879819dc698533b48c434ee2c374a03d150bdd834fe39501db65532312" 출고표 29번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 현재 bytes를 64자리 digest로 evidence에 결박한다.
입력
"canonicalTextSha256"
결과·효과
관찰 상태 F03-029가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
30줄F03-L30 } 출고표 30번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
입력
이전 줄의 상태와 SECURITIES
결과·효과
관찰 상태 F03-030가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
31줄F03-L31 ], 출고표 31번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 manifest.json의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 SECURITIES
결과·효과
관찰 상태 F03-031가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
manifest 문자열은 실행 결과가 아니다
32줄F03-L32 "authoredTarget": { 출고표 32번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 학습자가 직접 소유하는 main Java 경로와 starter/solution hash를 묶는다.
입력
"authoredTarget"
결과·효과
관찰 상태 F03-032가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
packaged test는 1_000→700/300만 assert한다
33줄F03-L33 "learnerPath": "src/main/java/com/example/financialcore/securities/CashWallet.java", 출고표 33번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 manifest.json의 다음 검증 또는 설명 단계를 구성한다.
입력
"learnerPath"
결과·효과
관찰 상태 F03-033가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
finalState 10_000은 별도 evidence가 필요하다
34줄F03-L34 "introducedAt": 25, 출고표 34번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 manifest.json의 다음 검증 또는 설명 단계를 구성한다.
입력
"introducedAt", 25
결과·효과
관찰 상태 F03-034가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
35줄F03-L35 "ownership": "LEARNER_AUTHORED", 출고표 35번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 manifest.json의 다음 검증 또는 설명 단계를 구성한다.
입력
"ownership", "LEARNER_AUTHORED"
결과·효과
관찰 상태 F03-035가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
36줄F03-L36 "starterAsset": "starter/src/main/java/com/example/financialcore/securities/CashWallet.java", 출고표 36번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 manifest.json의 다음 검증 또는 설명 단계를 구성한다.
입력
"starterAsset"
결과·효과
관찰 상태 F03-036가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
37줄F03-L37 "starterSha256": "b88925eec28e4c4afb8a9438f490ddb99670c69e33b70b746ee8e1cd6ffcdd2d", 출고표 37번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 starter 원시 bytes의 SHA-256을 manifest에 결박한다.
입력
"starterSha256"
결과·효과
관찰 상태 F03-037가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
manifest 문자열은 실행 결과가 아니다
38줄F03-L38 "starterCanonicalTextSha256": "b88925eec28e4c4afb8a9438f490ddb99670c69e33b70b746ee8e1cd6ffcdd2d", 출고표 38번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 현재 bytes를 64자리 digest로 evidence에 결박한다.
입력
"starterCanonicalTextSha256"
결과·효과
관찰 상태 F03-038가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
packaged test는 1_000→700/300만 assert한다
39줄F03-L39 "solutionAsset": "solution/src/main/java/com/example/financialcore/securities/CashWallet.java", 출고표 39번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 manifest.json의 다음 검증 또는 설명 단계를 구성한다.
입력
"solutionAsset"
결과·효과
관찰 상태 F03-039가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
finalState 10_000은 별도 evidence가 필요하다
40줄F03-L40 "solutionSha256": "cdf78c1f20d8cdbb6304d89c0d4298e65de7d4eb64b39812c37fda28f26fb411", 출고표 40번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 solution 원시 bytes의 SHA-256을 manifest에 결박한다.
입력
"solutionSha256"
결과·효과
관찰 상태 F03-040가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
41줄F03-L41 "solutionCanonicalTextSha256": "cdf78c1f20d8cdbb6304d89c0d4298e65de7d4eb64b39812c37fda28f26fb411" 출고표 41번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 현재 bytes를 64자리 digest로 evidence에 결박한다.
입력
"solutionCanonicalTextSha256"
결과·효과
관찰 상태 F03-041가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
42줄F03-L42 } 출고표 42번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
입력
이전 줄의 상태와 SECURITIES
결과·효과
관찰 상태 F03-042가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
43줄F03-L43 } 출고표 43번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
입력
이전 줄의 상태와 SECURITIES
결과·효과
관찰 상태 F03-043가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
manifest 문자열은 실행 결과가 아니다
05

STEP 05 / 13

원본 코드 조각

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

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

F03-C01 · 원문 1–12줄1–12줄
1–12줄 원본
{
  "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 보존",
F03-C02 · 원문 13–24줄13–24줄
13–24줄 원본
    "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",
F03-C03 · 원문 25–36줄25–36줄
25–36줄 원본
      "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",
F03-C04 · 원문 37–43줄37–43줄
37–43줄 원본
    "starterSha256": "b88925eec28e4c4afb8a9438f490ddb99670c69e33b70b746ee8e1cd6ffcdd2d",
    "starterCanonicalTextSha256": "b88925eec28e4c4afb8a9438f490ddb99670c69e33b70b746ee8e1cd6ffcdd2d",
    "solutionAsset": "solution/src/main/java/com/example/financialcore/securities/CashWallet.java",
    "solutionSha256": "cdf78c1f20d8cdbb6304d89c0d4298e65de7d4eb64b39812c37fda28f26fb411",
    "solutionCanonicalTextSha256": "cdf78c1f20d8cdbb6304d89c0d4298e65de7d4eb64b39812c37fda28f26fb411"
  }
}
06

STEP 06 / 13

코드 한 줄씩 한국어로 번역

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

전체 번역 43 / 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 또는 호출 범위를 닫는다.
07

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를 서로 대체하지 않는다.

실행 순서

  1. 기본 트랙은 SECURITIES(증권)이며, 명시적 CARD 선택은 기본값을 덮어쓴다. 실제 실행 전 최종 선택 한 개를 selected-track.csv·근거·state에 같은 값으로 기록하고 서로 다른 reference/learner root를 확인한다.
  2. Prepare→VerifyStarter→RecordRed→VerifySolution→RecordGreen→Cumulative→Review 순서를 지킨다.
  3. test를 소유한 세 phase에서만 native exit와 exact JUnit XML 수치를 판정한다.
  4. 다음 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 불변식히토리 → 니지카 → 료 → 키타
  1. 히토리

    progressive_contract가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 선택 트랙 selector·redMarker·starter/solution hash와 0/10_000 설명 계약을 고정한다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘packaged test는 1_000→700/300만 assert한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 progressive_contract와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

08

STEP 08 / 13

실제 값 따라가기

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

순서들어온 값코드가 하는 일나온 값·상태경계
입력SECURITIESsource 계약에 대입F03 실행/설명 시작 상태manifest 문자열은 실행 결과가 아니다
검증progressive_contractexpected와 actual 또는 형식 대조통과 또는 첫 mismatchpackaged test는 1_000→700/300만 assert한다
증거LEARNER_AUTHOREDmarker·hash·row를 같은 run에 연결범위가 적힌 evidence 후보이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
실제 값 — SECURITIES manifest — 현금 available+reserved 불변식히토리 → 니지카 → 료 → 키타
  1. 히토리

    W25_SECURITIES_RED_EXPECTED가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 선택 트랙 selector·redMarker·starter/solution hash와 0/10_000 설명 계약을 고정한다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘finalState 10_000은 별도 evidence가 필요하다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 W25_SECURITIES_RED_EXPECTED와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

09

STEP 09 / 13

Gradle·JUnit XML·PowerShell·SQL 내부에서 벌어지는 일

세 test phase, XML bytes archive, Review, 별도 Q41, USER_ATTESTED sealed 결과의 owner와 증명 범위를 구분합니다.

source/contract

manifest.json bytes와 track·phase·hash 계약을 읽는다.

SECURITIES 기본 선택과 파일 존재·phase 이름만으로 runtime Green을 주장할 수 없다. 실제 selected-track evidence와 실행 결과는 별도다.
execution/evidence

RecordRed·RecordGreen·Cumulative에서만 native exit와 exact JUnit XML을 만든다.

manifest 문자열은 실행 결과가 아니다
retention/review

XML bytes를 고유 파일로 보존하고 history hash와 묶은 뒤, Review는 기존 CumulativeGreen만 인용한다. Q41은 별도 PostgreSQL evidence, sealed official status는 user-attested evidence로 남긴다.

이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
첫 실패 경계 — SECURITIES manifest — 현금 available+reserved 불변식히토리 → 니지카 → 료 → 키타
  1. 히토리

    available=0,reserved=10_000가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 선택 트랙 selector·redMarker·starter/solution hash와 0/10_000 설명 계약을 고정한다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘reference와 learner root는 서로 달라야 한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 available=0,reserved=10_000와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

10

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이 생기지 않는다.

11

STEP 11 / 13

이 코드가 보장하지 않는 것

선택 미결정·10_000 finalState·XML 보존·Review/Q41/sealed official truth처럼 이 코드가 책임지지 않는 일을 분리합니다.

증명 범위

manifest 문자열은 실행 결과가 아니다

이 책임을 맡는 곳: runtime Gate
증명 범위

packaged test는 1_000→700/300만 assert한다

이 책임을 맡는 곳: external/human review
증명 범위

finalState 10_000은 별도 evidence가 필요하다

이 책임을 맡는 곳: release manifest
증명 범위

reference와 learner root는 서로 달라야 한다

이 책임을 맡는 곳: 운영 환경
증명하지 않는 범위 — SECURITIES manifest — 현금 available+reserved 불변식히토리 → 니지카 → 료 → 키타
  1. 히토리

    LEARNER_AUTHORED가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 선택 트랙 selector·redMarker·starter/solution hash와 0/10_000 설명 계약을 고정한다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 LEARNER_AUTHORED와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

12

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. 1. 앞에서 연 block 또는 호출 범위를 닫는다
  2. 2. manifest 형식 버전을 2로 고정한다
  3. 3. 이 계약이 W25에만 적용됨을 숫자로 고정한다
  4. 4. 이 manifest의 SECURITIES 또는 CARD 분기 identity를 고정할 뿐 실제 사용자 선택을 대신하지 않는다
  5. 5. manifest.json의 다음 검증 또는 설명 단계를 구성한다
  6. 6. manifest.json의 다음 검증 또는 설명 단계를 구성한다
  7. 7. manifest.json의 다음 검증 또는 설명 단계를 구성한다
  8. 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 책임을 설명할 수 있나?
13

STEP 13 / 13

전체 원본 source

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

원문 정본 전체 source 확인하기
패키지 정본 보조 계약 · exact W25 manifest bytestrack_learning_stages/securities/w25/manifest.jsonSHA-256 7100417457b6478e4130ebe0b8baf2663585f6d4ca476983b15eebde4ce65a81
SECURITIES manifest — 현금 available+reserved 불변식 전체
{
  "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"
  }
}
04

CARD manifest — 한도 available+used 불변식

track_learning_stages/card/w25/manifest.json

패키지 정본 보조 계약 · exact W25 manifest bytes · 정본 · W25-F04
43줄 연결43줄 번역4 chunks
01

STEP 01 / 13

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

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

오늘의 한 문장

선택 트랙 selector·redMarker·starter/solution hash와 0/10_000 설명 계약을 고정한다.

  1. CARD은 어느 source와 실제 결과에서 확인해야 할까?
  2. 첫 실패를 만드는 조건과 fail-closed 지점은 어디일까?
  3. 왜 ‘manifest 문자열은 실행 결과가 아니다’를 별도 경계로 남겨야 할까?
이 파일에서 끝까지 다시 쓰는 값CARDprogressive_contractW25_CARD_RED_EXPECTEDavailable=0,used=10_000LEARNER_AUTHORED
왜 필요한가 — CARD manifest — 한도 available+used 불변식히토리 → 니지카 → 료 → 키타
  1. 히토리

    CARD가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 선택 트랙 selector·redMarker·starter/solution hash와 0/10_000 설명 계약을 고정한다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘manifest 문자열은 실행 결과가 아니다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 CARD와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

02

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 확인을 대신하지 않는다.

03

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이며 실제 실행은 정확히 한 트랙에만 귀속한다
04

STEP 04 / 13

비유 ↔ 코드 전체 연결표

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

단어 몇 개만 뽑은 표가 아닙니다.패키지 정본 보조 계약 · exact W25 manifest bytes에서 비어 있지 않은 모든 줄을 원본 줄 번호 그대로 연결했습니다.43 / 43 연결
정확한 원본 줄STARRY 비유실제 뜻·입력·결과·한계
1줄F04-L01 { 출고표 1번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
입력
이전 줄의 상태와 CARD
결과·효과
관찰 상태 F04-001가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
manifest 문자열은 실행 결과가 아니다
2줄F04-L02 "schemaVersion": 2, 출고표 2번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 manifest 형식 버전을 2로 고정한다.
입력
"schemaVersion", 2
결과·효과
관찰 상태 F04-002가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
packaged test는 1_000→300/700만 assert한다
3줄F04-L03 "week": 25, 출고표 3번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 이 계약이 W25에만 적용됨을 숫자로 고정한다.
입력
"week", 25
결과·효과
관찰 상태 F04-003가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
finalState 10_000은 별도 evidence가 필요하다
4줄F04-L04 "track": "CARD", 출고표 4번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 이 manifest의 SECURITIES 또는 CARD 분기 identity를 고정할 뿐 실제 사용자 선택을 대신하지 않는다.
입력
"track", "CARD"
결과·효과
관찰 상태 F04-004가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
5줄F04-L05 "title": "한도 가용액·사용액 불변식", 출고표 5번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 manifest.json의 다음 검증 또는 설명 단계를 구성한다.
입력
"title", "한도 가용액·사용액 불변식"
결과·효과
관찰 상태 F04-005가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
6줄F04-L06 "claim": "hold 뒤 available+used 보존", 출고표 6번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 manifest.json의 다음 검증 또는 설명 단계를 구성한다.
입력
"claim", "hold 뒤 available+used 보존"
결과·효과
관찰 상태 F04-006가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
7줄F04-L07 "textEncoding": "UTF-8", 출고표 7번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 manifest.json의 다음 검증 또는 설명 단계를 구성한다.
입력
"textEncoding", "UTF-8"
결과·효과
관찰 상태 F04-007가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
manifest 문자열은 실행 결과가 아니다
8줄F04-L08 "newlinePolicy": "LF_CANONICAL_CRLF_EQUIVALENT", 출고표 8번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 manifest.json의 다음 검증 또는 설명 단계를 구성한다.
입력
"newlinePolicy", "LF_CANONICAL_CRLF_EQUIVALENT"
결과·효과
관찰 상태 F04-008가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
packaged test는 1_000→300/700만 assert한다
9줄F04-L09 "domainContract": { 출고표 9번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 불변식·실패 모드·최종 상태처럼 도메인 설명을 한 묶음으로 연다.
입력
"domainContract"
결과·효과
관찰 상태 F04-009가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
finalState 10_000은 별도 evidence가 필요하다
10줄F04-L10 "invariant": "hold 전후 availableLimit+usedAmount가 creditLimit와 같고 음수가 아니다.", 출고표 10번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 두 잔액의 합계 보존과 음수 금지라는 핵심 불변식을 설명한다.
입력
"invariant"
결과·효과
관찰 상태 F04-010가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
11줄F04-L11 "failureMode": "usedAmount 증가 누락으로 같은 한도를 반복 승인한다.", 출고표 11번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 차감 또는 증가 누락이 같은 돈·한도의 중복 사용으로 이어짐을 밝힌다.
입력
"failureMode", "usedAmount 증가 누락으로 같은 한도를 반복 승인한다."
결과·효과
관찰 상태 F04-011가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
12줄F04-L12 "implementationTarget": "src/main/java/com/example/financialcore/card/CardAccount.java :: 한도 가용액·사용액 불변식 :: hold 뒤 available+used 보존", 출고표 12번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 manifest.json의 다음 검증 또는 설명 단계를 구성한다.
입력
"implementationTarget"
결과·효과
관찰 상태 F04-012가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
13줄F04-L13 "finalState": "available=0, used=10_000", 출고표 13번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 PDF가 요구하는 10_000 시나리오를 설명용 계약에 고정하며 packaged 1_000→700/300 test의 자동 assertion과 분리한다.
입력
"finalState", "available=0, used=10_000"
결과·효과
관찰 상태 F04-013가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
manifest 문자열은 실행 결과가 아니다
14줄F04-L14 "recoveryFocus": "승인 전후 한도 두 값과 합계를 비교한다.", 출고표 14번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 manifest.json의 다음 검증 또는 설명 단계를 구성한다.
입력
"recoveryFocus", "승인 전후 한도 두 값과 합계를 비교한다."
결과·효과
관찰 상태 F04-014가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
packaged test는 1_000→300/700만 assert한다
15줄F04-L15 "interviewDefense": "카드 한도 hold는 사용액 증가와 가용 한도 감소를 함께 증명한다." 출고표 15번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 manifest.json의 다음 검증 또는 설명 단계를 구성한다.
입력
"interviewDefense", "카드 한도 hold는 사용액 증가와 가용 한도 감소를 함께 증명한다."
결과·효과
관찰 상태 F04-015가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
finalState 10_000은 별도 evidence가 필요하다
16줄F04-L16 }, 출고표 16번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 manifest.json의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 CARD
결과·효과
관찰 상태 F04-016가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
17줄F04-L17 "selector": "com.example.financialcore.card.W25CardLimitProgressiveTest", 출고표 17번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 선택 트랙의 정확한 JUnit suite 이름 하나를 지정한다.
입력
"selector"
결과·효과
관찰 상태 F04-017가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
18줄F04-L18 "testMethod": "progressive_contract", 출고표 18번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 progressive_contract 메서드 하나를 W25 proof 대상으로 지정한다.
입력
"testMethod", "progressive_contract"
결과·효과
관찰 상태 F04-018가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
19줄F04-L19 "redMarker": "W25_CARD_RED_EXPECTED", 출고표 19번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 의도한 Red 실패를 다른 실패와 구분할 marker를 고정한다.
입력
"redMarker", "W25_CARD_RED_EXPECTED"
결과·효과
관찰 상태 F04-019가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
manifest 문자열은 실행 결과가 아니다
20줄F04-L20 "predecessor": null, 출고표 20번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 manifest.json의 다음 검증 또는 설명 단계를 구성한다.
입력
"predecessor"
결과·효과
관찰 상태 F04-020가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
packaged test는 1_000→300/700만 assert한다
21줄F04-L21 "providedFiles": [], 출고표 21번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 manifest.json의 다음 검증 또는 설명 단계를 구성한다.
입력
"providedFiles"
결과·효과
관찰 상태 F04-021가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
finalState 10_000은 별도 evidence가 필요하다
22줄F04-L22 "testFiles": [ 출고표 22번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 manifest.json의 다음 검증 또는 설명 단계를 구성한다.
입력
"testFiles"
결과·효과
관찰 상태 F04-022가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
23줄F04-L23 { 출고표 23번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
입력
이전 줄의 상태와 CARD
결과·효과
관찰 상태 F04-023가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
24줄F04-L24 "learnerPath": "src/test/java/com/example/financialcore/card/W25CardLimitProgressiveTest.java", 출고표 24번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 manifest.json의 다음 검증 또는 설명 단계를 구성한다.
입력
"learnerPath"
결과·효과
관찰 상태 F04-024가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
25줄F04-L25 "asset": "tests/src/test/java/com/example/financialcore/card/W25CardLimitProgressiveTest.java", 출고표 25번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 manifest.json의 다음 검증 또는 설명 단계를 구성한다.
입력
"asset"
결과·효과
관찰 상태 F04-025가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
manifest 문자열은 실행 결과가 아니다
26줄F04-L26 "introducedAt": 25, 출고표 26번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 manifest.json의 다음 검증 또는 설명 단계를 구성한다.
입력
"introducedAt", 25
결과·효과
관찰 상태 F04-026가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
packaged test는 1_000→300/700만 assert한다
27줄F04-L27 "ownership": "PROVIDED_FIXTURE_VERIFIED", 출고표 27번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 manifest.json의 다음 검증 또는 설명 단계를 구성한다.
입력
"ownership", "PROVIDED_FIXTURE_VERIFIED"
결과·효과
관찰 상태 F04-027가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
finalState 10_000은 별도 evidence가 필요하다
28줄F04-L28 "sha256": "9cdba356b51a1b7c78fad4b1da205f021b67f17705cae12a0382cd835dda6459", 출고표 28번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 현재 bytes를 64자리 digest로 evidence에 결박한다.
입력
"sha256"
결과·효과
관찰 상태 F04-028가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
29줄F04-L29 "canonicalTextSha256": "9cdba356b51a1b7c78fad4b1da205f021b67f17705cae12a0382cd835dda6459" 출고표 29번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 현재 bytes를 64자리 digest로 evidence에 결박한다.
입력
"canonicalTextSha256"
결과·효과
관찰 상태 F04-029가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
30줄F04-L30 } 출고표 30번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
입력
이전 줄의 상태와 CARD
결과·효과
관찰 상태 F04-030가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
31줄F04-L31 ], 출고표 31번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 manifest.json의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 CARD
결과·효과
관찰 상태 F04-031가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
manifest 문자열은 실행 결과가 아니다
32줄F04-L32 "authoredTarget": { 출고표 32번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 학습자가 직접 소유하는 main Java 경로와 starter/solution hash를 묶는다.
입력
"authoredTarget"
결과·효과
관찰 상태 F04-032가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
packaged test는 1_000→300/700만 assert한다
33줄F04-L33 "learnerPath": "src/main/java/com/example/financialcore/card/CardAccount.java", 출고표 33번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 manifest.json의 다음 검증 또는 설명 단계를 구성한다.
입력
"learnerPath"
결과·효과
관찰 상태 F04-033가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
finalState 10_000은 별도 evidence가 필요하다
34줄F04-L34 "introducedAt": 25, 출고표 34번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 manifest.json의 다음 검증 또는 설명 단계를 구성한다.
입력
"introducedAt", 25
결과·효과
관찰 상태 F04-034가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
35줄F04-L35 "ownership": "LEARNER_AUTHORED", 출고표 35번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 manifest.json의 다음 검증 또는 설명 단계를 구성한다.
입력
"ownership", "LEARNER_AUTHORED"
결과·효과
관찰 상태 F04-035가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
36줄F04-L36 "starterAsset": "starter/src/main/java/com/example/financialcore/card/CardAccount.java", 출고표 36번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 manifest.json의 다음 검증 또는 설명 단계를 구성한다.
입력
"starterAsset"
결과·효과
관찰 상태 F04-036가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
37줄F04-L37 "starterSha256": "cc62b9dd28d90f23ada49f810436ed04ce2d604e6b902d72183a7887bbc07ea2", 출고표 37번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 starter 원시 bytes의 SHA-256을 manifest에 결박한다.
입력
"starterSha256"
결과·효과
관찰 상태 F04-037가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
manifest 문자열은 실행 결과가 아니다
38줄F04-L38 "starterCanonicalTextSha256": "cc62b9dd28d90f23ada49f810436ed04ce2d604e6b902d72183a7887bbc07ea2", 출고표 38번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 현재 bytes를 64자리 digest로 evidence에 결박한다.
입력
"starterCanonicalTextSha256"
결과·효과
관찰 상태 F04-038가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
packaged test는 1_000→300/700만 assert한다
39줄F04-L39 "solutionAsset": "solution/src/main/java/com/example/financialcore/card/CardAccount.java", 출고표 39번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 manifest.json의 다음 검증 또는 설명 단계를 구성한다.
입력
"solutionAsset"
결과·효과
관찰 상태 F04-039가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
finalState 10_000은 별도 evidence가 필요하다
40줄F04-L40 "solutionSha256": "3a142277feffdb89156bbce21dde495d299564a7c1c4a036f7d4505f96fea0e3", 출고표 40번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 solution 원시 bytes의 SHA-256을 manifest에 결박한다.
입력
"solutionSha256"
결과·효과
관찰 상태 F04-040가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
41줄F04-L41 "solutionCanonicalTextSha256": "3a142277feffdb89156bbce21dde495d299564a7c1c4a036f7d4505f96fea0e3" 출고표 41번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 현재 bytes를 64자리 digest로 evidence에 결박한다.
입력
"solutionCanonicalTextSha256"
결과·효과
관찰 상태 F04-041가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
42줄F04-L42 } 출고표 42번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
입력
이전 줄의 상태와 CARD
결과·효과
관찰 상태 F04-042가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
43줄F04-L43 } 출고표 43번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
입력
이전 줄의 상태와 CARD
결과·효과
관찰 상태 F04-043가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
manifest 문자열은 실행 결과가 아니다
05

STEP 05 / 13

원본 코드 조각

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

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

F04-C01 · 원문 1–12줄1–12줄
1–12줄 원본
{
  "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 보존",
F04-C02 · 원문 13–24줄13–24줄
13–24줄 원본
    "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",
F04-C03 · 원문 25–36줄25–36줄
25–36줄 원본
      "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",
F04-C04 · 원문 37–43줄37–43줄
37–43줄 원본
    "starterSha256": "cc62b9dd28d90f23ada49f810436ed04ce2d604e6b902d72183a7887bbc07ea2",
    "starterCanonicalTextSha256": "cc62b9dd28d90f23ada49f810436ed04ce2d604e6b902d72183a7887bbc07ea2",
    "solutionAsset": "solution/src/main/java/com/example/financialcore/card/CardAccount.java",
    "solutionSha256": "3a142277feffdb89156bbce21dde495d299564a7c1c4a036f7d4505f96fea0e3",
    "solutionCanonicalTextSha256": "3a142277feffdb89156bbce21dde495d299564a7c1c4a036f7d4505f96fea0e3"
  }
}
06

STEP 06 / 13

코드 한 줄씩 한국어로 번역

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

전체 번역 43 / 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 또는 호출 범위를 닫는다.
07

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를 서로 대체하지 않는다.

실행 순서

  1. 기본 트랙은 SECURITIES(증권)이며, 명시적 CARD 선택은 기본값을 덮어쓴다. 실제 실행 전 최종 선택 한 개를 selected-track.csv·근거·state에 같은 값으로 기록하고 서로 다른 reference/learner root를 확인한다.
  2. Prepare→VerifyStarter→RecordRed→VerifySolution→RecordGreen→Cumulative→Review 순서를 지킨다.
  3. test를 소유한 세 phase에서만 native exit와 exact JUnit XML 수치를 판정한다.
  4. 다음 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 불변식히토리 → 니지카 → 료 → 키타
  1. 히토리

    progressive_contract가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 선택 트랙 selector·redMarker·starter/solution hash와 0/10_000 설명 계약을 고정한다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘packaged test는 1_000→300/700만 assert한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 progressive_contract와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

08

STEP 08 / 13

실제 값 따라가기

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

순서들어온 값코드가 하는 일나온 값·상태경계
입력CARDsource 계약에 대입F04 실행/설명 시작 상태manifest 문자열은 실행 결과가 아니다
검증progressive_contractexpected와 actual 또는 형식 대조통과 또는 첫 mismatchpackaged test는 1_000→300/700만 assert한다
증거LEARNER_AUTHOREDmarker·hash·row를 같은 run에 연결범위가 적힌 evidence 후보이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
실제 값 — CARD manifest — 한도 available+used 불변식히토리 → 니지카 → 료 → 키타
  1. 히토리

    W25_CARD_RED_EXPECTED가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 선택 트랙 selector·redMarker·starter/solution hash와 0/10_000 설명 계약을 고정한다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘finalState 10_000은 별도 evidence가 필요하다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 W25_CARD_RED_EXPECTED와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

09

STEP 09 / 13

Gradle·JUnit XML·PowerShell·SQL 내부에서 벌어지는 일

세 test phase, XML bytes archive, Review, 별도 Q41, USER_ATTESTED sealed 결과의 owner와 증명 범위를 구분합니다.

source/contract

manifest.json bytes와 track·phase·hash 계약을 읽는다.

SECURITIES 기본 선택과 파일 존재·phase 이름만으로 runtime Green을 주장할 수 없다. 실제 selected-track evidence와 실행 결과는 별도다.
execution/evidence

RecordRed·RecordGreen·Cumulative에서만 native exit와 exact JUnit XML을 만든다.

manifest 문자열은 실행 결과가 아니다
retention/review

XML bytes를 고유 파일로 보존하고 history hash와 묶은 뒤, Review는 기존 CumulativeGreen만 인용한다. Q41은 별도 PostgreSQL evidence, sealed official status는 user-attested evidence로 남긴다.

이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
첫 실패 경계 — CARD manifest — 한도 available+used 불변식히토리 → 니지카 → 료 → 키타
  1. 히토리

    available=0,used=10_000가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 선택 트랙 selector·redMarker·starter/solution hash와 0/10_000 설명 계약을 고정한다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘reference와 learner root는 서로 달라야 한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 available=0,used=10_000와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

10

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이 생기지 않는다.

11

STEP 11 / 13

이 코드가 보장하지 않는 것

선택 미결정·10_000 finalState·XML 보존·Review/Q41/sealed official truth처럼 이 코드가 책임지지 않는 일을 분리합니다.

증명 범위

manifest 문자열은 실행 결과가 아니다

이 책임을 맡는 곳: runtime Gate
증명 범위

packaged test는 1_000→300/700만 assert한다

이 책임을 맡는 곳: external/human review
증명 범위

finalState 10_000은 별도 evidence가 필요하다

이 책임을 맡는 곳: release manifest
증명 범위

reference와 learner root는 서로 달라야 한다

이 책임을 맡는 곳: 운영 환경
증명하지 않는 범위 — CARD manifest — 한도 available+used 불변식히토리 → 니지카 → 료 → 키타
  1. 히토리

    LEARNER_AUTHORED가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 선택 트랙 selector·redMarker·starter/solution hash와 0/10_000 설명 계약을 고정한다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 LEARNER_AUTHORED와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

12

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. 1. 앞에서 연 block 또는 호출 범위를 닫는다
  2. 2. manifest 형식 버전을 2로 고정한다
  3. 3. 이 계약이 W25에만 적용됨을 숫자로 고정한다
  4. 4. 이 manifest의 SECURITIES 또는 CARD 분기 identity를 고정할 뿐 실제 사용자 선택을 대신하지 않는다
  5. 5. manifest.json의 다음 검증 또는 설명 단계를 구성한다
  6. 6. manifest.json의 다음 검증 또는 설명 단계를 구성한다
  7. 7. manifest.json의 다음 검증 또는 설명 단계를 구성한다
  8. 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 책임을 설명할 수 있나?
13

STEP 13 / 13

전체 원본 source

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

원문 정본 전체 source 확인하기
패키지 정본 보조 계약 · exact W25 manifest bytestrack_learning_stages/card/w25/manifest.jsonSHA-256 b05874190fe5408160acfb99087a0b5124d1a9e98673a28f658e462dfed4c5de
CARD manifest — 한도 available+used 불변식 전체
{
  "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"
  }
}
05

W25CashWalletProgressiveTest — 1_000에서 300 예약

track_learning_stages/securities/w25/tests/src/test/java/com/example/financialcore/securities/W25CashWalletProgressiveTest.java

패키지 정본 보조 계약 · exact JUnit test bytes · 정본 · W25-F05
12줄 연결12줄 번역2 chunks
01

STEP 01 / 13

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

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

오늘의 한 문장

starter의 가용 현금 차감 누락을 Red로 만들고 solution의 available=700·reserved=300을 검증한다.

  1. open=1_000은 어느 source와 실제 결과에서 확인해야 할까?
  2. 첫 실패를 만드는 조건과 fail-closed 지점은 어디일까?
  3. 왜 ‘test 하나에는 assertion 두 개가 있다’를 별도 경계로 남겨야 할까?
이 파일에서 끝까지 다시 쓰는 값open=1_000reserve=300available=700reserved=300W25_SECURITIES_RED_EXPECTED
왜 필요한가 — W25CashWalletProgressiveTest — 1_000에서 300 예약히토리 → 니지카 → 료 → 키타
  1. 히토리

    open=1_000가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 starter의 가용 현금 차감 누락을 Red로 만들고 solution의 available=700·reserved=300을 검증한다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘test 하나에는 assertion 두 개가 있다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 open=1_000와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

02

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 확인을 대신하지 않는다.

03

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이며 실제 실행은 정확히 한 트랙에만 귀속한다
04

STEP 04 / 13

비유 ↔ 코드 전체 연결표

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

단어 몇 개만 뽑은 표가 아닙니다.패키지 정본 보조 계약 · exact JUnit test bytes에서 비어 있지 않은 모든 줄을 원본 줄 번호 그대로 연결했습니다.12 / 12 연결
정확한 원본 줄STARRY 비유실제 뜻·입력·결과·한계
1줄F05-L01 package com.example.financialcore.securities; 출고표 1번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 W25CashWalletProgressiveTest.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 open=1_000
결과·효과
관찰 상태 F05-001가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
test 하나에는 assertion 두 개가 있다
3줄F05-L03 import org.junit.jupiter.api.Test; 출고표 3번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 W25CashWalletProgressiveTest.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 open=1_000
결과·효과
관찰 상태 F05-003가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
DB/JPA·동시성은 검증하지 않는다
4줄F05-L04 import static org.assertj.core.api.Assertions.*; 출고표 4번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 W25CashWalletProgressiveTest.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 open=1_000
결과·효과
관찰 상태 F05-004가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
6줄F05-L06 class W25CashWalletProgressiveTest { 출고표 6번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 조건·반복·함수의 실행 block을 연다.
입력
이전 줄의 상태와 open=1_000
결과·효과
관찰 상태 F05-006가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
7줄F05-L07 @Test 출고표 7번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 JUnit이 실행할 progressive contract test임을 표시한다.
입력
이전 줄의 상태와 open=1_000
결과·효과
관찰 상태 F05-007가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
test 하나에는 assertion 두 개가 있다
8줄F05-L08 void progressive_contract() { 출고표 8번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 선택 트랙의 W25 불변식을 한 개의 점진 test로 검증한다.
입력
이전 줄의 상태와 open=1_000
결과·효과
관찰 상태 F05-008가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
0/10_000 finalState를 검증하지 않는다
9줄F05-L09 CashWallet wallet=CashWallet.open("INV-UNIT",1_000); 출고표 9번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 가용 현금 1_000으로 securities 지갑을 만든다.
입력
"INV-UNIT"
결과·효과
관찰 상태 F05-009가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
DB/JPA·동시성은 검증하지 않는다
10줄F05-L10 wallet.reserve(300); 출고표 10번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 현금 300을 예약하여 available과 reserved 변화가 함께 일어나게 한다.
입력
300
결과·효과
관찰 상태 F05-010가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
11줄F05-L11 assertThat(wallet.getAvailableCash()).as("W25_SECURITIES_RED_EXPECTED").isEqualTo(700); 출고표 11번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 예약 뒤 가용 현금이 700인지 관찰한다.
입력
"W25_SECURITIES_RED_EXPECTED", 700
결과·효과
관찰 상태 F05-011가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
12줄F05-L12 assertThat(wallet.getReservedCash()).isEqualTo(300); 출고표 12번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 예약 뒤 예약 현금이 300인지 관찰한다.
입력
300
결과·효과
관찰 상태 F05-012가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
13줄F05-L13 } 출고표 13번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
입력
이전 줄의 상태와 open=1_000
결과·효과
관찰 상태 F05-013가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
test 하나에는 assertion 두 개가 있다
14줄F05-L14 } 출고표 14번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
입력
이전 줄의 상태와 open=1_000
결과·효과
관찰 상태 F05-014가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
0/10_000 finalState를 검증하지 않는다
05

STEP 05 / 13

원본 코드 조각

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

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

F05-C01 · 원문 1–12줄1–12줄
1–12줄 원본
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);
F05-C02 · 원문 13–14줄13–14줄
13–14줄 원본
    }
}
06

STEP 06 / 13

코드 한 줄씩 한국어로 번역

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

전체 번역 12 / 12

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

원본한국어 번역
1package com.example.financialcore.securities;실행 의미: W25CashWalletProgressiveTest.java의 다음 검증 또는 설명 단계를 구성한다.
3import org.junit.jupiter.api.Test;실행 의미: W25CashWalletProgressiveTest.java의 다음 검증 또는 설명 단계를 구성한다.
4import static org.assertj.core.api.Assertions.*;실행 의미: W25CashWalletProgressiveTest.java의 다음 검증 또는 설명 단계를 구성한다.
6class 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 또는 호출 범위를 닫는다.
07

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를 서로 대체하지 않는다.

실행 순서

  1. 기본 트랙은 SECURITIES(증권)이며, 명시적 CARD 선택은 기본값을 덮어쓴다. 실제 실행 전 최종 선택 한 개를 selected-track.csv·근거·state에 같은 값으로 기록하고 서로 다른 reference/learner root를 확인한다.
  2. Prepare→VerifyStarter→RecordRed→VerifySolution→RecordGreen→Cumulative→Review 순서를 지킨다.
  3. test를 소유한 세 phase에서만 native exit와 exact JUnit XML 수치를 판정한다.
  4. 다음 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 예약히토리 → 니지카 → 료 → 키타
  1. 히토리

    reserve=300가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 starter의 가용 현금 차감 누락을 Red로 만들고 solution의 available=700·reserved=300을 검증한다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘0/10_000 finalState를 검증하지 않는다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 reserve=300와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

08

STEP 08 / 13

실제 값 따라가기

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

순서들어온 값코드가 하는 일나온 값·상태경계
입력open=1_000source 계약에 대입F05 실행/설명 시작 상태test 하나에는 assertion 두 개가 있다
검증reserve=300expected와 actual 또는 형식 대조통과 또는 첫 mismatch0/10_000 finalState를 검증하지 않는다
증거W25_SECURITIES_RED_EXPECTEDmarker·hash·row를 같은 run에 연결범위가 적힌 evidence 후보이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
실제 값 — W25CashWalletProgressiveTest — 1_000에서 300 예약히토리 → 니지카 → 료 → 키타
  1. 히토리

    available=700가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 starter의 가용 현금 차감 누락을 Red로 만들고 solution의 available=700·reserved=300을 검증한다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘DB/JPA·동시성은 검증하지 않는다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 available=700와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

09

STEP 09 / 13

Gradle·JUnit XML·PowerShell·SQL 내부에서 벌어지는 일

세 test phase, XML bytes archive, Review, 별도 Q41, USER_ATTESTED sealed 결과의 owner와 증명 범위를 구분합니다.

source/contract

W25CashWalletProgressiveTest.java bytes와 track·phase·hash 계약을 읽는다.

SECURITIES 기본 선택과 파일 존재·phase 이름만으로 runtime Green을 주장할 수 없다. 실제 selected-track evidence와 실행 결과는 별도다.
execution/evidence

RecordRed·RecordGreen·Cumulative에서만 native exit와 exact JUnit XML을 만든다.

test 하나에는 assertion 두 개가 있다
retention/review

XML bytes를 고유 파일로 보존하고 history hash와 묶은 뒤, Review는 기존 CumulativeGreen만 인용한다. Q41은 별도 PostgreSQL evidence, sealed official status는 user-attested evidence로 남긴다.

이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다

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

progressive_contract

Arrange · 준비
  • 선택 트랙 객체를 1_000으로 생성한다.
Act · 행동
  • SECURITIES는 reserve(300), CARD는 hold(300)을 한 번 호출한다.
Assert · 확인
  • 두 잔액이 각각 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 예약히토리 → 니지카 → 료 → 키타
  1. 히토리

    reserved=300가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 starter의 가용 현금 차감 누락을 Red로 만들고 solution의 available=700·reserved=300을 검증한다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘reference와 learner root는 서로 달라야 한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 reserved=300와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

10

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이 생기지 않는다.

11

STEP 11 / 13

이 코드가 보장하지 않는 것

선택 미결정·10_000 finalState·XML 보존·Review/Q41/sealed official truth처럼 이 코드가 책임지지 않는 일을 분리합니다.

증명 범위

test 하나에는 assertion 두 개가 있다

이 책임을 맡는 곳: runtime Gate
증명 범위

0/10_000 finalState를 검증하지 않는다

이 책임을 맡는 곳: external/human review
증명 범위

DB/JPA·동시성은 검증하지 않는다

이 책임을 맡는 곳: release manifest
증명 범위

reference와 learner root는 서로 달라야 한다

이 책임을 맡는 곳: 운영 환경
증명하지 않는 범위 — W25CashWalletProgressiveTest — 1_000에서 300 예약히토리 → 니지카 → 료 → 키타
  1. 히토리

    W25_SECURITIES_RED_EXPECTED가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 starter의 가용 현금 차감 누락을 Red로 만들고 solution의 available=700·reserved=300을 검증한다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 W25_SECURITIES_RED_EXPECTED와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

12

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. 1. W25CashWalletProgressiveTest.java의 다음 검증 또는 설명 단계를 구성한다
  2. 3. W25CashWalletProgressiveTest.java의 다음 검증 또는 설명 단계를 구성한다
  3. 4. W25CashWalletProgressiveTest.java의 다음 검증 또는 설명 단계를 구성한다
  4. 6. 조건·반복·함수의 실행 block을 연다
  5. 7. JUnit이 실행할 progressive contract test임을 표시한다
  6. 8. 선택 트랙의 W25 불변식을 한 개의 점진 test로 검증한다
  7. 9. 가용 현금 1_000으로 securities 지갑을 만든다
  8. 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 책임을 설명할 수 있나?
13

STEP 13 / 13

전체 원본 source

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

원문 정본 전체 source 확인하기
패키지 정본 보조 계약 · exact JUnit test bytestrack_learning_stages/securities/w25/tests/src/test/java/com/example/financialcore/securities/W25CashWalletProgressiveTest.javaSHA-256 f45516879819dc698533b48c434ee2c374a03d150bdd834fe39501db65532312
W25CashWalletProgressiveTest — 1_000에서 300 예약 전체
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);
    }
}
06

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-F06
11줄 연결11줄 번역2 chunks
01

STEP 01 / 13

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

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

오늘의 한 문장

starter의 사용액 증가 누락을 Red로 만들고 solution의 used=300·available=700을 검증한다.

  1. open=1_000은 어느 source와 실제 결과에서 확인해야 할까?
  2. 첫 실패를 만드는 조건과 fail-closed 지점은 어디일까?
  3. 왜 ‘test 하나에는 assertion 두 개가 있다’를 별도 경계로 남겨야 할까?
이 파일에서 끝까지 다시 쓰는 값open=1_000hold=300used=300available=700W25_CARD_RED_EXPECTED
왜 필요한가 — W25CardLimitProgressiveTest — 1_000에서 300 hold히토리 → 니지카 → 료 → 키타
  1. 히토리

    open=1_000가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 starter의 사용액 증가 누락을 Red로 만들고 solution의 used=300·available=700을 검증한다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘test 하나에는 assertion 두 개가 있다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 open=1_000와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

02

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 확인을 대신하지 않는다.

03

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이며 실제 실행은 정확히 한 트랙에만 귀속한다
04

STEP 04 / 13

비유 ↔ 코드 전체 연결표

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

단어 몇 개만 뽑은 표가 아닙니다.패키지 정본 보조 계약 · exact JUnit test bytes에서 비어 있지 않은 모든 줄을 원본 줄 번호 그대로 연결했습니다.11 / 11 연결
정확한 원본 줄STARRY 비유실제 뜻·입력·결과·한계
1줄F06-L01 package com.example.financialcore.card; 출고표 1번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 W25CardLimitProgressiveTest.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 open=1_000
결과·효과
관찰 상태 F06-001가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
test 하나에는 assertion 두 개가 있다
3줄F06-L03 import org.junit.jupiter.api.Test; 출고표 3번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 W25CardLimitProgressiveTest.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 open=1_000
결과·효과
관찰 상태 F06-003가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
DB/JPA·동시성은 검증하지 않는다
4줄F06-L04 import static org.assertj.core.api.Assertions.*; 출고표 4번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 W25CardLimitProgressiveTest.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 open=1_000
결과·효과
관찰 상태 F06-004가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
6줄F06-L06 class W25CardLimitProgressiveTest { 출고표 6번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 조건·반복·함수의 실행 block을 연다.
입력
이전 줄의 상태와 open=1_000
결과·효과
관찰 상태 F06-006가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
7줄F06-L07 @Test 출고표 7번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 JUnit이 실행할 progressive contract test임을 표시한다.
입력
이전 줄의 상태와 open=1_000
결과·효과
관찰 상태 F06-007가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
test 하나에는 assertion 두 개가 있다
8줄F06-L08 void progressive_contract() { 출고표 8번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 선택 트랙의 W25 불변식을 한 개의 점진 test로 검증한다.
입력
이전 줄의 상태와 open=1_000
결과·효과
관찰 상태 F06-008가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
0/10_000 finalState를 검증하지 않는다
9줄F06-L09 CardAccount account=CardAccount.open("CARD-UNIT",1_000);account.hold(300); 출고표 9번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 신용 한도 1_000으로 card 계정을 만든다.
입력
"CARD-UNIT", 300
결과·효과
관찰 상태 F06-009가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
DB/JPA·동시성은 검증하지 않는다
10줄F06-L10 assertThat(account.getUsedAmount()).as("W25_CARD_RED_EXPECTED").isEqualTo(300); 출고표 10번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 hold 뒤 사용액이 300인지 관찰한다.
입력
"W25_CARD_RED_EXPECTED", 300
결과·효과
관찰 상태 F06-010가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
11줄F06-L11 assertThat(account.availableAmount()).isEqualTo(700); 출고표 11번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 hold 뒤 가용 한도가 700인지 관찰한다.
입력
700
결과·효과
관찰 상태 F06-011가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
12줄F06-L12 } 출고표 12번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
입력
이전 줄의 상태와 open=1_000
결과·효과
관찰 상태 F06-012가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
13줄F06-L13 } 출고표 13번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
입력
이전 줄의 상태와 open=1_000
결과·효과
관찰 상태 F06-013가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
test 하나에는 assertion 두 개가 있다
05

STEP 05 / 13

원본 코드 조각

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

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

F06-C01 · 원문 1–12줄1–12줄
1–12줄 원본
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);
    }
F06-C02 · 원문 13–13줄13–13줄
13–13줄 원본
}
06

STEP 06 / 13

코드 한 줄씩 한국어로 번역

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

전체 번역 11 / 11

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

원본한국어 번역
1package com.example.financialcore.card;실행 의미: W25CardLimitProgressiveTest.java의 다음 검증 또는 설명 단계를 구성한다.
3import org.junit.jupiter.api.Test;실행 의미: W25CardLimitProgressiveTest.java의 다음 검증 또는 설명 단계를 구성한다.
4import static org.assertj.core.api.Assertions.*;실행 의미: W25CardLimitProgressiveTest.java의 다음 검증 또는 설명 단계를 구성한다.
6class 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 또는 호출 범위를 닫는다.
07

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를 서로 대체하지 않는다.

실행 순서

  1. 기본 트랙은 SECURITIES(증권)이며, 명시적 CARD 선택은 기본값을 덮어쓴다. 실제 실행 전 최종 선택 한 개를 selected-track.csv·근거·state에 같은 값으로 기록하고 서로 다른 reference/learner root를 확인한다.
  2. Prepare→VerifyStarter→RecordRed→VerifySolution→RecordGreen→Cumulative→Review 순서를 지킨다.
  3. test를 소유한 세 phase에서만 native exit와 exact JUnit XML 수치를 판정한다.
  4. 다음 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히토리 → 니지카 → 료 → 키타
  1. 히토리

    hold=300가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 starter의 사용액 증가 누락을 Red로 만들고 solution의 used=300·available=700을 검증한다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘0/10_000 finalState를 검증하지 않는다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 hold=300와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

08

STEP 08 / 13

실제 값 따라가기

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

순서들어온 값코드가 하는 일나온 값·상태경계
입력open=1_000source 계약에 대입F06 실행/설명 시작 상태test 하나에는 assertion 두 개가 있다
검증hold=300expected와 actual 또는 형식 대조통과 또는 첫 mismatch0/10_000 finalState를 검증하지 않는다
증거W25_CARD_RED_EXPECTEDmarker·hash·row를 같은 run에 연결범위가 적힌 evidence 후보이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
실제 값 — W25CardLimitProgressiveTest — 1_000에서 300 hold히토리 → 니지카 → 료 → 키타
  1. 히토리

    used=300가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 starter의 사용액 증가 누락을 Red로 만들고 solution의 used=300·available=700을 검증한다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘DB/JPA·동시성은 검증하지 않는다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 used=300와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

09

STEP 09 / 13

Gradle·JUnit XML·PowerShell·SQL 내부에서 벌어지는 일

세 test phase, XML bytes archive, Review, 별도 Q41, USER_ATTESTED sealed 결과의 owner와 증명 범위를 구분합니다.

source/contract

W25CardLimitProgressiveTest.java bytes와 track·phase·hash 계약을 읽는다.

SECURITIES 기본 선택과 파일 존재·phase 이름만으로 runtime Green을 주장할 수 없다. 실제 selected-track evidence와 실행 결과는 별도다.
execution/evidence

RecordRed·RecordGreen·Cumulative에서만 native exit와 exact JUnit XML을 만든다.

test 하나에는 assertion 두 개가 있다
retention/review

XML bytes를 고유 파일로 보존하고 history hash와 묶은 뒤, Review는 기존 CumulativeGreen만 인용한다. Q41은 별도 PostgreSQL evidence, sealed official status는 user-attested evidence로 남긴다.

이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다

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

progressive_contract

Arrange · 준비
  • 선택 트랙 객체를 1_000으로 생성한다.
Act · 행동
  • SECURITIES는 reserve(300), CARD는 hold(300)을 한 번 호출한다.
Assert · 확인
  • 두 잔액이 각각 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히토리 → 니지카 → 료 → 키타
  1. 히토리

    available=700가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 starter의 사용액 증가 누락을 Red로 만들고 solution의 used=300·available=700을 검증한다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘reference와 learner root는 서로 달라야 한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 available=700와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

10

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이 생기지 않는다.

11

STEP 11 / 13

이 코드가 보장하지 않는 것

선택 미결정·10_000 finalState·XML 보존·Review/Q41/sealed official truth처럼 이 코드가 책임지지 않는 일을 분리합니다.

증명 범위

test 하나에는 assertion 두 개가 있다

이 책임을 맡는 곳: runtime Gate
증명 범위

0/10_000 finalState를 검증하지 않는다

이 책임을 맡는 곳: external/human review
증명 범위

DB/JPA·동시성은 검증하지 않는다

이 책임을 맡는 곳: release manifest
증명 범위

reference와 learner root는 서로 달라야 한다

이 책임을 맡는 곳: 운영 환경
증명하지 않는 범위 — W25CardLimitProgressiveTest — 1_000에서 300 hold히토리 → 니지카 → 료 → 키타
  1. 히토리

    W25_CARD_RED_EXPECTED가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 starter의 사용액 증가 누락을 Red로 만들고 solution의 used=300·available=700을 검증한다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 W25_CARD_RED_EXPECTED와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

12

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. 1. W25CardLimitProgressiveTest.java의 다음 검증 또는 설명 단계를 구성한다
  2. 3. W25CardLimitProgressiveTest.java의 다음 검증 또는 설명 단계를 구성한다
  3. 4. W25CardLimitProgressiveTest.java의 다음 검증 또는 설명 단계를 구성한다
  4. 6. 조건·반복·함수의 실행 block을 연다
  5. 7. JUnit이 실행할 progressive contract test임을 표시한다
  6. 8. 선택 트랙의 W25 불변식을 한 개의 점진 test로 검증한다
  7. 9. 신용 한도 1_000으로 card 계정을 만든다
  8. 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 책임을 설명할 수 있나?
13

STEP 13 / 13

전체 원본 source

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

원문 정본 전체 source 확인하기
패키지 정본 보조 계약 · exact JUnit test bytestrack_learning_stages/card/w25/tests/src/test/java/com/example/financialcore/card/W25CardLimitProgressiveTest.javaSHA-256 9cdba356b51a1b7c78fad4b1da205f021b67f17705cae12a0382cd835dda6459
W25CardLimitProgressiveTest — 1_000에서 300 hold 전체
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);
    }
}
07

D1 Prepare — 선택 근거와 Prepared state

illustrative/powershell/W25-D1-prepare.ps1

학습용 예시 · W25 phase wrapper · 정본 답안 아님 · 로컬 미실행 · 학습용 예시 · 정본 답안 아님 · NOT_RUN · W25-F07
36줄 연결36줄 번역4 chunks
01

STEP 01 / 13

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

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

오늘의 한 문장

FINANCIAL_IT_SELECTED_TRACK이 비어 있으면 SECURITIES를 기본값으로 사용하고 exactly one selected-track.csv를 만든 뒤 Prepare가 test fixture·leak 경계만 검증했는지 확인한다.

  1. default=SECURITIES은 어느 source와 실제 결과에서 확인해야 할까?
  2. 첫 실패를 만드는 조건과 fail-closed 지점은 어디일까?
  3. 왜 ‘SECURITIES 기본 선택은 runtime 실행 결과가 아니다’를 별도 경계로 남겨야 할까?
이 파일에서 끝까지 다시 쓰는 값default=SECURITIESSECURITIES xor CARDselected-track.csvPreparedruntime_claim=false
왜 필요한가 — D1 Prepare — 선택 근거와 Prepared state히토리 → 니지카 → 료 → 키타
  1. 히토리

    default=SECURITIES가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 FINANCIAL_IT_SELECTED_TRACK이 비어 있으면 SECURITIES를 기본값으로 사용하고 exactly one selected-track.csv를 만든 뒤 Prepare가 test fixture·leak 경계만 검증했는지 확인한다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘SECURITIES 기본 선택은 runtime 실행 결과가 아니다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 default=SECURITIES와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

02

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 확인을 대신하지 않는다.

03

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을 실행하지 않았다
04

STEP 04 / 13

비유 ↔ 코드 전체 연결표

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

단어 몇 개만 뽑은 표가 아닙니다.학습용 예시 · W25 phase wrapper · 정본 답안 아님 · 로컬 미실행에서 비어 있지 않은 모든 줄을 원본 줄 번호 그대로 연결했습니다.36 / 36 연결
정확한 원본 줄STARRY 비유실제 뜻·입력·결과·한계
1줄F07-L01 # W25 PDF p3-p7의 Prepare 흐름을 읽기 좋게 정리한 학습용 예시다. 출고표 1번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다.
입력
이전 줄의 상태와 default=SECURITIES
결과·효과
관찰 상태 F07-001가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
SECURITIES 기본 선택은 runtime 실행 결과가 아니다
2줄F07-L02 # packaged reference source가 아니며, Gradle/JUnit Green을 주장하지 않는다. 출고표 2번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다.
입력
이전 줄의 상태와 default=SECURITIES
결과·효과
관찰 상태 F07-002가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
Prepare는 target hash·Gradle·XML·finalState를 검증하지 않는다
3줄F07-L03 $ErrorActionPreference = 'Stop' 출고표 3번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 PowerShell 오류를 계속 진행하지 않고 중단시키는 기본 정책을 둔다.
입력
$ErrorActionPreference, 'Stop'
결과·효과
관찰 상태 F07-003가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
5줄F07-L05 foreach ($Name in @('FINANCIAL_IT_REFERENCE_ROOT', 'FINANCIAL_IT_LEARNER_ROOT')) { 출고표 5번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 고정 목록의 각 항목에 같은 검사를 반복 적용한다.
입력
$Name, 'FINANCIAL_IT_REFERENCE_ROOT', 'FINANCIAL_IT_LEARNER_ROOT'
결과·효과
관찰 상태 F07-005가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
6줄F07-L06 $Value = [Environment]::GetEnvironmentVariable($Name) 출고표 6번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
입력
$Value, $Name
결과·효과
관찰 상태 F07-006가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
SECURITIES 기본 선택은 runtime 실행 결과가 아니다
7줄F07-L07 if ([string]::IsNullOrWhiteSpace($Value)) { throw "$Name must be set" } 출고표 7번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
입력
$Value, "$Name must be set"
결과·효과
관찰 상태 F07-007가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
Prepare는 target hash·Gradle·XML·finalState를 검증하지 않는다
8줄F07-L08 } 출고표 8번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
입력
이전 줄의 상태와 default=SECURITIES
결과·효과
관찰 상태 F07-008가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
9줄F07-L09 $ReferenceRoot = (Resolve-Path -LiteralPath $env:FINANCIAL_IT_REFERENCE_ROOT).Path 출고표 9번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 입력 경로를 실제 절대 경로로 확인한다.
입력
$ReferenceRoot, $env
결과·효과
관찰 상태 F07-009가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
10줄F07-L10 $LearnerRoot = (Resolve-Path -LiteralPath $env:FINANCIAL_IT_LEARNER_ROOT).Path 출고표 10번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 입력 경로를 실제 절대 경로로 확인한다.
입력
$LearnerRoot, $env
결과·효과
관찰 상태 F07-010가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
11줄F07-L11 if ([string]::Equals($ReferenceRoot, $LearnerRoot, [StringComparison]::OrdinalIgnoreCase)) { 출고표 11번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 조건·반복·함수의 실행 block을 연다.
입력
$ReferenceRoot, $LearnerRoot
결과·효과
관찰 상태 F07-011가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
SECURITIES 기본 선택은 runtime 실행 결과가 아니다
12줄F07-L12 throw 'reference and learner roots must be different' 출고표 12번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
입력
이전 줄의 상태와 default=SECURITIES
결과·효과
관찰 상태 F07-012가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
Prepare는 target hash·Gradle·XML·finalState를 검증하지 않는다
13줄F07-L13 } 출고표 13번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
입력
이전 줄의 상태와 default=SECURITIES
결과·효과
관찰 상태 F07-013가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
14줄F07-L14 $TrackValue = [Environment]::GetEnvironmentVariable('FINANCIAL_IT_SELECTED_TRACK') 출고표 14번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
입력
$TrackValue, 'FINANCIAL_IT_SELECTED_TRACK'
결과·효과
관찰 상태 F07-014가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
15줄F07-L15 $Track = if ([string]::IsNullOrWhiteSpace($TrackValue)) { 'SECURITIES' } else { $TrackValue.ToUpperInvariant() } 출고표 15번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
입력
$Track, $TrackValue, 'SECURITIES'
결과·효과
관찰 상태 F07-015가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
16줄F07-L16 if ($Track -cnotin @('SECURITIES', 'CARD')) { throw 'track must be SECURITIES or CARD' } 출고표 16번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
입력
$Track, 'SECURITIES', 'CARD'
결과·효과
관찰 상태 F07-016가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
SECURITIES 기본 선택은 runtime 실행 결과가 아니다
17줄F07-L17 if ([string]::IsNullOrWhiteSpace($env:FINANCIAL_IT_TRACK_RATIONALE)) { 출고표 17번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 조건·반복·함수의 실행 block을 연다.
입력
$env
결과·효과
관찰 상태 F07-017가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
Prepare는 target hash·Gradle·XML·finalState를 검증하지 않는다
18줄F07-L18 throw 'FINANCIAL_IT_TRACK_RATIONALE must contain the learner decision' 출고표 18번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
입력
이전 줄의 상태와 default=SECURITIES
결과·효과
관찰 상태 F07-018가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
19줄F07-L19 } 출고표 19번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
입력
이전 줄의 상태와 default=SECURITIES
결과·효과
관찰 상태 F07-019가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
21줄F07-L21 $EvidenceDir = Join-Path $LearnerRoot 'evidence\w25' 출고표 21번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
입력
$EvidenceDir, $LearnerRoot, 'evidence\w25'
결과·효과
관찰 상태 F07-021가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
SECURITIES 기본 선택은 runtime 실행 결과가 아니다
22줄F07-L22 New-Item -ItemType Directory -Force -Path $EvidenceDir | Out-Null 출고표 22번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 Markdown 표 또는 PowerShell pipeline에서 값을 열이나 다음 명령으로 연결한다.
입력
$EvidenceDir
결과·효과
관찰 상태 F07-022가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
Prepare는 target hash·Gradle·XML·finalState를 검증하지 않는다
23줄F07-L23 [pscustomobject][ordered]@{ 출고표 23번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 조건·반복·함수의 실행 block을 연다.
입력
이전 줄의 상태와 default=SECURITIES
결과·효과
관찰 상태 F07-023가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
24줄F07-L24 selected_track = $Track 출고표 24번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 W25-D1-prepare.ps1의 다음 검증 또는 설명 단계를 구성한다.
입력
$Track
결과·효과
관찰 상태 F07-024가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
25줄F07-L25 decided_at = (Get-Date).ToUniversalTime().ToString('o') 출고표 25번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 W25-D1-prepare.ps1의 다음 검증 또는 설명 단계를 구성한다.
입력
'o'
결과·효과
관찰 상태 F07-025가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
26줄F07-L26 rationale = $env:FINANCIAL_IT_TRACK_RATIONALE 출고표 26번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 W25-D1-prepare.ps1의 다음 검증 또는 설명 단계를 구성한다.
입력
$env
결과·효과
관찰 상태 F07-026가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
SECURITIES 기본 선택은 runtime 실행 결과가 아니다
27줄F07-L27 evidence = 'evidence/w25/selection-rationale.txt' 출고표 27번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 W25-D1-prepare.ps1의 다음 검증 또는 설명 단계를 구성한다.
입력
'evidence/w25/selection-rationale.txt'
결과·효과
관찰 상태 F07-027가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
Prepare는 target hash·Gradle·XML·finalState를 검증하지 않는다
28줄F07-L28 } | Export-Csv -LiteralPath (Join-Path $EvidenceDir 'selected-track.csv') -NoTypeInformation -Encoding utf8 출고표 28번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 Markdown 표 또는 PowerShell pipeline에서 값을 열이나 다음 명령으로 연결한다.
입력
$EvidenceDir, 'selected-track.csv'
결과·효과
관찰 상태 F07-028가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
29줄F07-L29 Set-Content -LiteralPath (Join-Path $EvidenceDir 'selection-rationale.txt') -Encoding utf8 -Value $env:FINANCIAL_IT_TRACK_RATIONALE 출고표 29번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 W25-D1-prepare.ps1의 다음 검증 또는 설명 단계를 구성한다.
입력
$EvidenceDir, 'selection-rationale.txt', $env
결과·효과
관찰 상태 F07-029가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
31줄F07-L31 $Runner = Join-Path $ReferenceRoot 'scripts\apply-track-learning-stage.ps1' 출고표 31번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
입력
$Runner, $ReferenceRoot, 'scripts\apply-track-learning-stage.ps1'
결과·효과
관찰 상태 F07-031가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
SECURITIES 기본 선택은 runtime 실행 결과가 아니다
32줄F07-L32 & powershell.exe -NoProfile -ExecutionPolicy Bypass -File $Runner ` 출고표 32번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 W25-D1-prepare.ps1의 다음 검증 또는 설명 단계를 구성한다.
입력
$Runner
결과·효과
관찰 상태 F07-032가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
Prepare는 target hash·Gradle·XML·finalState를 검증하지 않는다
33줄F07-L33 -ReferenceRoot $ReferenceRoot -LearnerRoot $LearnerRoot -Week 25 -Phase Prepare -TimeoutSeconds 1200 출고표 33번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 W25-D1-prepare.ps1의 다음 검증 또는 설명 단계를 구성한다.
입력
$ReferenceRoot, $LearnerRoot, 25
결과·효과
관찰 상태 F07-033가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
34줄F07-L34 if ($LASTEXITCODE -ne 0) { throw "W25 Prepare native exit=$LASTEXITCODE" } 출고표 34번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 native process 종료 코드를 검사해 실패를 놓치지 않는다.
입력
$LASTEXITCODE, 0, "W25 Prepare native exit=$LASTEXITCODE"
결과·효과
관찰 상태 F07-034가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
36줄F07-L36 $State = Get-Content -Raw -LiteralPath (Join-Path $LearnerRoot '.track-learning-stage.json') | ConvertFrom-Json 출고표 36번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 JSON text를 필드로 접근 가능한 PowerShell object로 바꾼다.
입력
$State, $LearnerRoot, '.track-learning-stage.json'
결과·효과
관찰 상태 F07-036가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
SECURITIES 기본 선택은 runtime 실행 결과가 아니다
37줄F07-L37 if ($State.week -ne 25 -or $State.track -cne $Track -or $State.phase -cne 'Prepared') { 출고표 37번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 조건·반복·함수의 실행 block을 연다.
입력
$State, 25, $State
결과·효과
관찰 상태 F07-037가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
Prepare는 target hash·Gradle·XML·finalState를 검증하지 않는다
38줄F07-L38 throw 'W25 Prepare state mismatch' 출고표 38번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
입력
'W25 Prepare state mismatch'
결과·효과
관찰 상태 F07-038가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
39줄F07-L39 } 출고표 39번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
입력
이전 줄의 상태와 default=SECURITIES
결과·효과
관찰 상태 F07-039가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
40줄F07-L40 'W25_PREPARE_VERIFIED phase=Prepared runtime_claim=false' 출고표 40번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 W25-D1-prepare.ps1의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 default=SECURITIES
결과·효과
관찰 상태 F07-040가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
05

STEP 05 / 13

원본 코드 조각

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

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

F07-C01 · 원문 1–12줄1–12줄
1–12줄 원본
# 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'
F07-C02 · 원문 13–24줄13–24줄
13–24줄 원본
}
$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
F07-C03 · 원문 25–36줄25–36줄
25–36줄 원본
  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
F07-C04 · 원문 37–40줄37–40줄
37–40줄 원본
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'
06

STEP 06 / 13

코드 한 줄씩 한국어로 번역

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

전체 번역 36 / 36

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

원본한국어 번역
1# W25 PDF p3-p7의 Prepare 흐름을 읽기 좋게 정리한 학습용 예시다.문서 의미: 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다.
2# packaged reference source가 아니며, Gradle/JUnit Green을 주장하지 않는다.문서 의미: 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다.
3$ErrorActionPreference = 'Stop'실행 의미: PowerShell 오류를 계속 진행하지 않고 중단시키는 기본 정책을 둔다.
5foreach ($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실행 의미: 입력 경로를 실제 절대 경로로 확인한다.
11if ([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 변수에 저장한다.
16if ($Track -cnotin @('SECURITIES', 'CARD')) { throw 'track must be SECURITIES or CARD' }실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
17if ([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 변수에 저장한다.
22New-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에서 값을 열이나 다음 명령으로 연결한다.
29Set-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의 다음 검증 또는 설명 단계를 구성한다.
34if ($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로 바꾼다.
37if ($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의 다음 검증 또는 설명 단계를 구성한다.
07

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를 서로 대체하지 않는다.

실행 순서

  1. 기본 트랙은 SECURITIES(증권)이며, 명시적 CARD 선택은 기본값을 덮어쓴다. 실제 실행 전 최종 선택 한 개를 selected-track.csv·근거·state에 같은 값으로 기록하고 서로 다른 reference/learner root를 확인한다.
  2. Prepare→VerifyStarter→RecordRed→VerifySolution→RecordGreen→Cumulative→Review 순서를 지킨다.
  3. test를 소유한 세 phase에서만 native exit와 exact JUnit XML 수치를 판정한다.
  4. 다음 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히토리 → 니지카 → 료 → 키타
  1. 히토리

    SECURITIES xor CARD가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 FINANCIAL_IT_SELECTED_TRACK이 비어 있으면 SECURITIES를 기본값으로 사용하고 exactly one selected-track.csv를 만든 뒤 Prepare가 test fixture·leak 경계만 검증했는지 확인한다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘Prepare는 target hash·Gradle·XML·finalState를 검증하지 않는다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 SECURITIES xor CARD와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

08

STEP 08 / 13

실제 값 따라가기

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

순서들어온 값코드가 하는 일나온 값·상태경계
입력default=SECURITIESsource 계약에 대입F07 실행/설명 시작 상태SECURITIES 기본 선택은 runtime 실행 결과가 아니다
검증SECURITIES xor CARDexpected와 actual 또는 형식 대조통과 또는 첫 mismatchPrepare는 target hash·Gradle·XML·finalState를 검증하지 않는다
증거runtime_claim=falsemarker·hash·row를 같은 run에 연결범위가 적힌 evidence 후보이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
실제 값 — D1 Prepare — 선택 근거와 Prepared state히토리 → 니지카 → 료 → 키타
  1. 히토리

    selected-track.csv가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 FINANCIAL_IT_SELECTED_TRACK이 비어 있으면 SECURITIES를 기본값으로 사용하고 exactly one selected-track.csv를 만든 뒤 Prepare가 test fixture·leak 경계만 검증했는지 확인한다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘reference와 learner root는 서로 달라야 한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 selected-track.csv와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

09

STEP 09 / 13

Gradle·JUnit XML·PowerShell·SQL 내부에서 벌어지는 일

세 test phase, XML bytes archive, Review, 별도 Q41, USER_ATTESTED sealed 결과의 owner와 증명 범위를 구분합니다.

source/contract

W25-D1-prepare.ps1 bytes와 track·phase·hash 계약을 읽는다.

SECURITIES 기본 선택과 파일 존재·phase 이름만으로 runtime Green을 주장할 수 없다. 실제 selected-track evidence와 실행 결과는 별도다.
execution/evidence

RecordRed·RecordGreen·Cumulative에서만 native exit와 exact JUnit XML을 만든다.

SECURITIES 기본 선택은 runtime 실행 결과가 아니다
retention/review

XML bytes를 고유 파일로 보존하고 history hash와 묶은 뒤, Review는 기존 CumulativeGreen만 인용한다. Q41은 별도 PostgreSQL evidence, sealed official status는 user-attested evidence로 남긴다.

이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
첫 실패 경계 — D1 Prepare — 선택 근거와 Prepared state히토리 → 니지카 → 료 → 키타
  1. 히토리

    Prepared가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 FINANCIAL_IT_SELECTED_TRACK이 비어 있으면 SECURITIES를 기본값으로 사용하고 exactly one selected-track.csv를 만든 뒤 Prepare가 test fixture·leak 경계만 검증했는지 확인한다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 Prepared와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

10

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이 생기지 않는다.

11

STEP 11 / 13

이 코드가 보장하지 않는 것

선택 미결정·10_000 finalState·XML 보존·Review/Q41/sealed official truth처럼 이 코드가 책임지지 않는 일을 분리합니다.

증명 범위

SECURITIES 기본 선택은 runtime 실행 결과가 아니다

이 책임을 맡는 곳: runtime Gate
증명 범위

Prepare는 target hash·Gradle·XML·finalState를 검증하지 않는다

이 책임을 맡는 곳: external/human review
증명 범위

reference와 learner root는 서로 달라야 한다

이 책임을 맡는 곳: release manifest
증명 범위

기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다

이 책임을 맡는 곳: 운영 환경
증명하지 않는 범위 — D1 Prepare — 선택 근거와 Prepared state히토리 → 니지카 → 료 → 키타
  1. 히토리

    runtime_claim=false가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 FINANCIAL_IT_SELECTED_TRACK이 비어 있으면 SECURITIES를 기본값으로 사용하고 exactly one selected-track.csv를 만든 뒤 Prepare가 test fixture·leak 경계만 검증했는지 확인한다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 runtime_claim=false와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

12

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. 1. 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다
  2. 2. 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다
  3. 3. PowerShell 오류를 계속 진행하지 않고 중단시키는 기본 정책을 둔다
  4. 5. 고정 목록의 각 항목에 같은 검사를 반복 적용한다
  5. 6. 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다
  6. 7. 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다
  7. 8. 앞에서 연 block 또는 호출 범위를 닫는다
  8. 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 책임을 설명할 수 있나?
13

STEP 13 / 13

전체 원본 source

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

학습용 예시 전체 확인하기 · 정본 답안 아님 · NOT_RUN
학습용 예시 · W25 phase wrapper · 정본 답안 아님 · 로컬 미실행illustrative/powershell/W25-D1-prepare.ps1SHA-256 41a9b52b4512d45b1d0a4327229584fac5af60ef3ba9b98b9b037d776f062b07
D1 Prepare — 선택 근거와 Prepared state 전체
# 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'
08

SECURITIES starter CashWallet — available 차감 누락

track_learning_stages/securities/w25/starter/src/main/java/com/example/financialcore/securities/CashWallet.java

PDF 전문 정본 · learner starter Java · 정본 · W25-F08
56줄 연결56줄 번역6 chunks
01

STEP 01 / 13

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

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

오늘의 한 문장

reserve가 reserved만 늘려 같은 현금을 다시 예약할 수 있는 의도한 Red 반례를 읽는다.

  1. availableCash=1_000은 어느 source와 실제 결과에서 확인해야 할까?
  2. 첫 실패를 만드는 조건과 fail-closed 지점은 어디일까?
  3. 왜 ‘reference asset을 복사했다고 learner authorship이 되지 않는다’를 별도 경계로 남겨야 할까?
이 파일에서 끝까지 다시 쓰는 값availableCash=1_000reservedCash=0reserve(300)available remains 1_000RED comment
왜 필요한가 — SECURITIES starter CashWallet — available 차감 누락히토리 → 니지카 → 료 → 키타
  1. 히토리

    availableCash=1_000가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 reserve가 reserved만 늘려 같은 현금을 다시 예약할 수 있는 의도한 Red 반례를 읽는다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘reference asset을 복사했다고 learner authorship이 되지 않는다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 availableCash=1_000와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

02

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 확인을 대신하지 않는다.

03

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이며 실제 실행은 정확히 한 트랙에만 귀속한다
04

STEP 04 / 13

비유 ↔ 코드 전체 연결표

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

단어 몇 개만 뽑은 표가 아닙니다.PDF 전문 정본 · learner starter Java에서 비어 있지 않은 모든 줄을 원본 줄 번호 그대로 연결했습니다.56 / 56 연결
정확한 원본 줄STARRY 비유실제 뜻·입력·결과·한계
1줄F08-L01 package com.example.financialcore.securities; 출고표 1번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 availableCash=1_000
결과·효과
관찰 상태 F08-001가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference asset을 복사했다고 learner authorship이 되지 않는다
3줄F08-L03 import jakarta.persistence.Column; 출고표 3번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 availableCash=1_000
결과·효과
관찰 상태 F08-003가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
선택하지 않은 트랙은 N-A_UNSELECTED
4줄F08-L04 import jakarta.persistence.Entity; 출고표 4번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 availableCash=1_000
결과·효과
관찰 상태 F08-004가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
5줄F08-L05 import jakarta.persistence.GeneratedValue; 출고표 5번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 availableCash=1_000
결과·효과
관찰 상태 F08-005가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
6줄F08-L06 import jakarta.persistence.GenerationType; 출고표 6번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 availableCash=1_000
결과·효과
관찰 상태 F08-006가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
7줄F08-L07 import jakarta.persistence.Id; 출고표 7번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 availableCash=1_000
결과·효과
관찰 상태 F08-007가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference asset을 복사했다고 learner authorship이 되지 않는다
8줄F08-L08 import jakarta.persistence.Table; 출고표 8번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 availableCash=1_000
결과·효과
관찰 상태 F08-008가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
UTF-8 BOM은 runtime이 거절한다
9줄F08-L09 import jakarta.persistence.Version; 출고표 9번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 availableCash=1_000
결과·효과
관찰 상태 F08-009가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
선택하지 않은 트랙은 N-A_UNSELECTED
11줄F08-L11 @Entity 출고표 11번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 availableCash=1_000
결과·효과
관찰 상태 F08-011가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
12줄F08-L12 @Table(name = "securities_cash_wallet") 출고표 12번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
입력
"securities_cash_wallet"
결과·효과
관찰 상태 F08-012가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
13줄F08-L13 public class CashWallet { 출고표 13번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 조건·반복·함수의 실행 block을 연다.
입력
이전 줄의 상태와 availableCash=1_000
결과·효과
관찰 상태 F08-013가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference asset을 복사했다고 learner authorship이 되지 않는다
14줄F08-L14 @Id 출고표 14번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 availableCash=1_000
결과·효과
관찰 상태 F08-014가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
UTF-8 BOM은 runtime이 거절한다
15줄F08-L15 @GeneratedValue(strategy = GenerationType.IDENTITY) 출고표 15번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 availableCash=1_000
결과·효과
관찰 상태 F08-015가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
선택하지 않은 트랙은 N-A_UNSELECTED
16줄F08-L16 private Long id; 출고표 16번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 availableCash=1_000
결과·효과
관찰 상태 F08-016가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
18줄F08-L18 @Column(name = "investor_key", nullable = false, unique = true, length = 64) 출고표 18번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
입력
"investor_key", 64
결과·효과
관찰 상태 F08-018가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
19줄F08-L19 private String investorKey; 출고표 19번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 availableCash=1_000
결과·효과
관찰 상태 F08-019가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference asset을 복사했다고 learner authorship이 되지 않는다
21줄F08-L21 @Column(name = "available_cash", nullable = false) 출고표 21번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
입력
"available_cash"
결과·효과
관찰 상태 F08-021가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
선택하지 않은 트랙은 N-A_UNSELECTED
22줄F08-L22 private long availableCash; 출고표 22번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 availableCash=1_000
결과·효과
관찰 상태 F08-022가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
24줄F08-L24 @Column(name = "reserved_cash", nullable = false) 출고표 24번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
입력
"reserved_cash"
결과·효과
관찰 상태 F08-024가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
25줄F08-L25 private long reservedCash; 출고표 25번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 availableCash=1_000
결과·효과
관찰 상태 F08-025가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference asset을 복사했다고 learner authorship이 되지 않는다
27줄F08-L27 @Version 출고표 27번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 availableCash=1_000
결과·효과
관찰 상태 F08-027가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
선택하지 않은 트랙은 N-A_UNSELECTED
28줄F08-L28 private long version; 출고표 28번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 availableCash=1_000
결과·효과
관찰 상태 F08-028가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
30줄F08-L30 protected CashWallet() {} 출고표 30번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 availableCash=1_000
결과·효과
관찰 상태 F08-030가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
32줄F08-L32 private CashWallet(String investorKey, long availableCash) { 출고표 32번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 조건·반복·함수의 실행 block을 연다.
입력
이전 줄의 상태와 availableCash=1_000
결과·효과
관찰 상태 F08-032가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
UTF-8 BOM은 runtime이 거절한다
33줄F08-L33 if (investorKey == null || investorKey.isBlank()) throw new IllegalArgumentException("investorKey"); 출고표 33번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
입력
"investorKey"
결과·효과
관찰 상태 F08-033가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
선택하지 않은 트랙은 N-A_UNSELECTED
34줄F08-L34 if (availableCash < 0) throw new IllegalArgumentException("availableCash"); 출고표 34번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
입력
0, "availableCash"
결과·효과
관찰 상태 F08-034가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
35줄F08-L35 this.investorKey = investorKey; 출고표 35번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 availableCash=1_000
결과·효과
관찰 상태 F08-035가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
36줄F08-L36 this.availableCash = availableCash; 출고표 36번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 availableCash=1_000
결과·효과
관찰 상태 F08-036가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
37줄F08-L37 } 출고표 37번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
입력
이전 줄의 상태와 availableCash=1_000
결과·효과
관찰 상태 F08-037가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference asset을 복사했다고 learner authorship이 되지 않는다
39줄F08-L39 public static CashWallet open(String investorKey, long availableCash) { 출고표 39번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 조건·반복·함수의 실행 block을 연다.
입력
이전 줄의 상태와 availableCash=1_000
결과·효과
관찰 상태 F08-039가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
선택하지 않은 트랙은 N-A_UNSELECTED
40줄F08-L40 return new CashWallet(investorKey, availableCash); 출고표 40번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 availableCash=1_000
결과·효과
관찰 상태 F08-040가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
41줄F08-L41 } 출고표 41번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
입력
이전 줄의 상태와 availableCash=1_000
결과·효과
관찰 상태 F08-041가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
43줄F08-L43 public void reserve(long amount) { 출고표 43번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 조건·반복·함수의 실행 block을 연다.
입력
이전 줄의 상태와 availableCash=1_000
결과·효과
관찰 상태 F08-043가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference asset을 복사했다고 learner authorship이 되지 않는다
44줄F08-L44 if (amount <= 0) throw new IllegalArgumentException("amount"); 출고표 44번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
입력
0, "amount"
결과·효과
관찰 상태 F08-044가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
UTF-8 BOM은 runtime이 거절한다
45줄F08-L45 if (availableCash < amount) throw new IllegalStateException("INSUFFICIENT_AVAILABLE_CASH"); 출고표 45번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
입력
"INSUFFICIENT_AVAILABLE_CASH"
결과·효과
관찰 상태 F08-045가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
선택하지 않은 트랙은 N-A_UNSELECTED
46줄F08-L46 // RED: available cash is not reduced 출고표 46번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 availableCash=1_000
결과·효과
관찰 상태 F08-046가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
47줄F08-L47 reservedCash = Math.addExact(reservedCash, amount); 출고표 47번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 availableCash=1_000
결과·효과
관찰 상태 F08-047가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
48줄F08-L48 } 출고표 48번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
입력
이전 줄의 상태와 availableCash=1_000
결과·효과
관찰 상태 F08-048가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
50줄F08-L50 public void settle(long reservedAmount, long executedAmount) { 출고표 50번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 조건·반복·함수의 실행 block을 연다.
입력
이전 줄의 상태와 availableCash=1_000
결과·효과
관찰 상태 F08-050가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
UTF-8 BOM은 runtime이 거절한다
51줄F08-L51 if (reservedAmount <= 0 || executedAmount <= 0 || executedAmount > reservedAmount) { 출고표 51번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 Markdown 표 또는 PowerShell pipeline에서 값을 열이나 다음 명령으로 연결한다.
입력
0, 0
결과·효과
관찰 상태 F08-051가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
선택하지 않은 트랙은 N-A_UNSELECTED
52줄F08-L52 throw new IllegalArgumentException("settlement amount"); 출고표 52번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
입력
"settlement amount"
결과·효과
관찰 상태 F08-052가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
53줄F08-L53 } 출고표 53번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
입력
이전 줄의 상태와 availableCash=1_000
결과·효과
관찰 상태 F08-053가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
54줄F08-L54 if (reservedCash < reservedAmount) throw new IllegalStateException("RESERVATION_MISMATCH"); 출고표 54번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
입력
"RESERVATION_MISMATCH"
결과·효과
관찰 상태 F08-054가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
55줄F08-L55 reservedCash -= reservedAmount; 출고표 55번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 availableCash=1_000
결과·효과
관찰 상태 F08-055가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference asset을 복사했다고 learner authorship이 되지 않는다
56줄F08-L56 availableCash = Math.addExact(availableCash, reservedAmount - executedAmount); 출고표 56번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 availableCash=1_000
결과·효과
관찰 상태 F08-056가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
UTF-8 BOM은 runtime이 거절한다
57줄F08-L57 } 출고표 57번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
입력
이전 줄의 상태와 availableCash=1_000
결과·효과
관찰 상태 F08-057가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
선택하지 않은 트랙은 N-A_UNSELECTED
59줄F08-L59 public void releaseReservation(long amount) { 출고표 59번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 조건·반복·함수의 실행 block을 연다.
입력
이전 줄의 상태와 availableCash=1_000
결과·효과
관찰 상태 F08-059가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
60줄F08-L60 if (amount <= 0 || reservedCash < amount) throw new IllegalArgumentException("amount"); 출고표 60번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
입력
0, "amount"
결과·효과
관찰 상태 F08-060가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
61줄F08-L61 reservedCash -= amount; 출고표 61번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 availableCash=1_000
결과·효과
관찰 상태 F08-061가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference asset을 복사했다고 learner authorship이 되지 않는다
62줄F08-L62 availableCash = Math.addExact(availableCash, amount); 출고표 62번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 availableCash=1_000
결과·효과
관찰 상태 F08-062가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
UTF-8 BOM은 runtime이 거절한다
63줄F08-L63 } 출고표 63번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
입력
이전 줄의 상태와 availableCash=1_000
결과·효과
관찰 상태 F08-063가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
선택하지 않은 트랙은 N-A_UNSELECTED
65줄F08-L65 public Long getId() { return id; } 출고표 65번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 availableCash=1_000
결과·효과
관찰 상태 F08-065가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
66줄F08-L66 public String getInvestorKey() { return investorKey; } 출고표 66번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 availableCash=1_000
결과·효과
관찰 상태 F08-066가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
67줄F08-L67 public long getAvailableCash() { return availableCash; } 출고표 67번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 예약 뒤 가용 현금이 700인지 관찰한다.
입력
이전 줄의 상태와 availableCash=1_000
결과·효과
관찰 상태 F08-067가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference asset을 복사했다고 learner authorship이 되지 않는다
68줄F08-L68 public long getReservedCash() { return reservedCash; } 출고표 68번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 예약 뒤 예약 현금이 300인지 관찰한다.
입력
이전 줄의 상태와 availableCash=1_000
결과·효과
관찰 상태 F08-068가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
UTF-8 BOM은 runtime이 거절한다
69줄F08-L69 } 출고표 69번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
입력
이전 줄의 상태와 availableCash=1_000
결과·효과
관찰 상태 F08-069가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
선택하지 않은 트랙은 N-A_UNSELECTED
05

STEP 05 / 13

원본 코드 조각

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

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

F08-C01 · 원문 1–12줄1–12줄
1–12줄 원본
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")
F08-C02 · 원문 13–24줄13–24줄
13–24줄 원본
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)
F08-C03 · 원문 25–36줄25–36줄
25–36줄 원본
    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;
F08-C04 · 원문 37–48줄37–48줄
37–48줄 원본
    }

    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);
    }
F08-C05 · 원문 49–60줄49–60줄
49–60줄 원본

    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");
F08-C06 · 원문 61–69줄61–69줄
61–69줄 원본
        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; }
}
06

STEP 06 / 13

코드 한 줄씩 한국어로 번역

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

전체 번역 56 / 56

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

원본한국어 번역
1package com.example.financialcore.securities;실행 의미: CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
3import jakarta.persistence.Column;실행 의미: CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
4import jakarta.persistence.Entity;실행 의미: CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
5import jakarta.persistence.GeneratedValue;실행 의미: CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
6import jakarta.persistence.GenerationType;실행 의미: CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
7import jakarta.persistence.Id;실행 의미: CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
8import jakarta.persistence.Table;실행 의미: CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
9import jakarta.persistence.Version;실행 의미: CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
11@Entity실행 의미: CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
12@Table(name = "securities_cash_wallet")실행 의미: CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
13public 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 또는 호출 범위를 닫는다.
07

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를 서로 대체하지 않는다.

실행 순서

  1. 기본 트랙은 SECURITIES(증권)이며, 명시적 CARD 선택은 기본값을 덮어쓴다. 실제 실행 전 최종 선택 한 개를 selected-track.csv·근거·state에 같은 값으로 기록하고 서로 다른 reference/learner root를 확인한다.
  2. Prepare→VerifyStarter→RecordRed→VerifySolution→RecordGreen→Cumulative→Review 순서를 지킨다.
  3. test를 소유한 세 phase에서만 native exit와 exact JUnit XML 수치를 판정한다.
  4. 다음 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 차감 누락히토리 → 니지카 → 료 → 키타
  1. 히토리

    reservedCash=0가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 reserve가 reserved만 늘려 같은 현금을 다시 예약할 수 있는 의도한 Red 반례를 읽는다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘UTF-8 BOM은 runtime이 거절한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 reservedCash=0와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

08

STEP 08 / 13

실제 값 따라가기

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

순서들어온 값코드가 하는 일나온 값·상태경계
입력availableCash=1_000source 계약에 대입F08 실행/설명 시작 상태reference asset을 복사했다고 learner authorship이 되지 않는다
검증reservedCash=0expected와 actual 또는 형식 대조통과 또는 첫 mismatchUTF-8 BOM은 runtime이 거절한다
증거RED commentmarker·hash·row를 같은 run에 연결범위가 적힌 evidence 후보이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
실제 값 — SECURITIES starter CashWallet — available 차감 누락히토리 → 니지카 → 료 → 키타
  1. 히토리

    reserve(300)가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 reserve가 reserved만 늘려 같은 현금을 다시 예약할 수 있는 의도한 Red 반례를 읽는다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘선택하지 않은 트랙은 N-A_UNSELECTED’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 reserve(300)와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

09

STEP 09 / 13

Gradle·JUnit XML·PowerShell·SQL 내부에서 벌어지는 일

세 test phase, XML bytes archive, Review, 별도 Q41, USER_ATTESTED sealed 결과의 owner와 증명 범위를 구분합니다.

source/contract

CashWallet.java bytes와 track·phase·hash 계약을 읽는다.

SECURITIES 기본 선택과 파일 존재·phase 이름만으로 runtime Green을 주장할 수 없다. 실제 selected-track evidence와 실행 결과는 별도다.
execution/evidence

RecordRed·RecordGreen·Cumulative에서만 native exit와 exact JUnit XML을 만든다.

reference asset을 복사했다고 learner authorship이 되지 않는다
retention/review

XML bytes를 고유 파일로 보존하고 history hash와 묶은 뒤, Review는 기존 CumulativeGreen만 인용한다. Q41은 별도 PostgreSQL evidence, sealed official status는 user-attested evidence로 남긴다.

이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
첫 실패 경계 — SECURITIES starter CashWallet — available 차감 누락히토리 → 니지카 → 료 → 키타
  1. 히토리

    available remains 1_000가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 reserve가 reserved만 늘려 같은 현금을 다시 예약할 수 있는 의도한 Red 반례를 읽는다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘reference와 learner root는 서로 달라야 한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 available remains 1_000와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

10

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이 생기지 않는다.

11

STEP 11 / 13

이 코드가 보장하지 않는 것

선택 미결정·10_000 finalState·XML 보존·Review/Q41/sealed official truth처럼 이 코드가 책임지지 않는 일을 분리합니다.

증명 범위

reference asset을 복사했다고 learner authorship이 되지 않는다

이 책임을 맡는 곳: runtime Gate
증명 범위

UTF-8 BOM은 runtime이 거절한다

이 책임을 맡는 곳: external/human review
증명 범위

선택하지 않은 트랙은 N-A_UNSELECTED

이 책임을 맡는 곳: release manifest
증명 범위

reference와 learner root는 서로 달라야 한다

이 책임을 맡는 곳: 운영 환경
증명하지 않는 범위 — SECURITIES starter CashWallet — available 차감 누락히토리 → 니지카 → 료 → 키타
  1. 히토리

    RED comment가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 reserve가 reserved만 늘려 같은 현금을 다시 예약할 수 있는 의도한 Red 반례를 읽는다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 RED comment와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

12

STEP 12 / 13

직접 다시 써보기

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

1단계 · 뜻부터 복원

  • reserve가 reserved만 늘려 같은 현금을 다시 예약할 수 있는 의도한 Red 반례를 읽는다.
  • 핵심 값은 availableCash=1_000, reservedCash=0, reserve(300), available remains 1_000, RED comment다.

2단계 · 코드 조각 재조립

  1. 1. CashWallet.java의 다음 검증 또는 설명 단계를 구성한다
  2. 3. CashWallet.java의 다음 검증 또는 설명 단계를 구성한다
  3. 4. CashWallet.java의 다음 검증 또는 설명 단계를 구성한다
  4. 5. CashWallet.java의 다음 검증 또는 설명 단계를 구성한다
  5. 6. CashWallet.java의 다음 검증 또는 설명 단계를 구성한다
  6. 7. CashWallet.java의 다음 검증 또는 설명 단계를 구성한다
  7. 8. CashWallet.java의 다음 검증 또는 설명 단계를 구성한다
  8. 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 책임을 설명할 수 있나?
13

STEP 13 / 13

전체 원본 source

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

원문 정본 전체 source 확인하기
PDF 전문 정본 · learner starter Javatrack_learning_stages/securities/w25/starter/src/main/java/com/example/financialcore/securities/CashWallet.javaSHA-256 b88925eec28e4c4afb8a9438f490ddb99670c69e33b70b746ee8e1cd6ffcdd2d
SECURITIES starter CashWallet — available 차감 누락 전체
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; }
}
09

CARD starter CardAccount — usedAmount 증가 누락

track_learning_stages/card/w25/starter/src/main/java/com/example/financialcore/card/CardAccount.java

PDF 전문 정본 · learner starter Java · 정본 · W25-F09
46줄 연결46줄 번역5 chunks
01

STEP 01 / 13

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

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

오늘의 한 문장

hold가 사용액을 늘리지 않아 같은 한도를 반복 승인할 수 있는 의도한 Red 반례를 읽는다.

  1. creditLimit=1_000은 어느 source와 실제 결과에서 확인해야 할까?
  2. 첫 실패를 만드는 조건과 fail-closed 지점은 어디일까?
  3. 왜 ‘reference asset을 복사했다고 learner authorship이 되지 않는다’를 별도 경계로 남겨야 할까?
이 파일에서 끝까지 다시 쓰는 값creditLimit=1_000usedAmount=0hold(300)used remains 0RED comment
왜 필요한가 — CARD starter CardAccount — usedAmount 증가 누락히토리 → 니지카 → 료 → 키타
  1. 히토리

    creditLimit=1_000가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 hold가 사용액을 늘리지 않아 같은 한도를 반복 승인할 수 있는 의도한 Red 반례를 읽는다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘reference asset을 복사했다고 learner authorship이 되지 않는다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 creditLimit=1_000와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

02

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 확인을 대신하지 않는다.

03

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이며 실제 실행은 정확히 한 트랙에만 귀속한다
04

STEP 04 / 13

비유 ↔ 코드 전체 연결표

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

단어 몇 개만 뽑은 표가 아닙니다.PDF 전문 정본 · learner starter Java에서 비어 있지 않은 모든 줄을 원본 줄 번호 그대로 연결했습니다.46 / 46 연결
정확한 원본 줄STARRY 비유실제 뜻·입력·결과·한계
1줄F09-L01 package com.example.financialcore.card; 출고표 1번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 creditLimit=1_000
결과·효과
관찰 상태 F09-001가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference asset을 복사했다고 learner authorship이 되지 않는다
3줄F09-L03 import jakarta.persistence.Column; 출고표 3번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 creditLimit=1_000
결과·효과
관찰 상태 F09-003가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
선택하지 않은 트랙은 N-A_UNSELECTED
4줄F09-L04 import jakarta.persistence.Entity; 출고표 4번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 creditLimit=1_000
결과·효과
관찰 상태 F09-004가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
5줄F09-L05 import jakarta.persistence.GeneratedValue; 출고표 5번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 creditLimit=1_000
결과·효과
관찰 상태 F09-005가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
6줄F09-L06 import jakarta.persistence.GenerationType; 출고표 6번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 creditLimit=1_000
결과·효과
관찰 상태 F09-006가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
7줄F09-L07 import jakarta.persistence.Id; 출고표 7번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 creditLimit=1_000
결과·효과
관찰 상태 F09-007가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference asset을 복사했다고 learner authorship이 되지 않는다
8줄F09-L08 import jakarta.persistence.Table; 출고표 8번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 creditLimit=1_000
결과·효과
관찰 상태 F09-008가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
UTF-8 BOM은 runtime이 거절한다
9줄F09-L09 import jakarta.persistence.Version; 출고표 9번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 creditLimit=1_000
결과·효과
관찰 상태 F09-009가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
선택하지 않은 트랙은 N-A_UNSELECTED
11줄F09-L11 @Entity 출고표 11번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 creditLimit=1_000
결과·효과
관찰 상태 F09-011가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
12줄F09-L12 @Table(name = "card_account_template") 출고표 12번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
입력
"card_account_template"
결과·효과
관찰 상태 F09-012가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
13줄F09-L13 public class CardAccount { 출고표 13번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 조건·반복·함수의 실행 block을 연다.
입력
이전 줄의 상태와 creditLimit=1_000
결과·효과
관찰 상태 F09-013가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference asset을 복사했다고 learner authorship이 되지 않는다
14줄F09-L14 @Id 출고표 14번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 creditLimit=1_000
결과·효과
관찰 상태 F09-014가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
UTF-8 BOM은 runtime이 거절한다
15줄F09-L15 @GeneratedValue(strategy = GenerationType.IDENTITY) 출고표 15번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 creditLimit=1_000
결과·효과
관찰 상태 F09-015가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
선택하지 않은 트랙은 N-A_UNSELECTED
16줄F09-L16 private Long id; 출고표 16번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 creditLimit=1_000
결과·효과
관찰 상태 F09-016가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
18줄F09-L18 @Column(name = "account_key", nullable = false, unique = true, length = 64) 출고표 18번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
입력
"account_key", 64
결과·효과
관찰 상태 F09-018가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
19줄F09-L19 private String accountKey; 출고표 19번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 creditLimit=1_000
결과·효과
관찰 상태 F09-019가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference asset을 복사했다고 learner authorship이 되지 않는다
21줄F09-L21 @Column(name = "credit_limit", nullable = false) 출고표 21번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
입력
"credit_limit"
결과·효과
관찰 상태 F09-021가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
선택하지 않은 트랙은 N-A_UNSELECTED
22줄F09-L22 private long creditLimit; 출고표 22번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 creditLimit=1_000
결과·효과
관찰 상태 F09-022가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
24줄F09-L24 @Column(name = "used_amount", nullable = false) 출고표 24번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
입력
"used_amount"
결과·효과
관찰 상태 F09-024가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
25줄F09-L25 private long usedAmount; 출고표 25번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 creditLimit=1_000
결과·효과
관찰 상태 F09-025가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference asset을 복사했다고 learner authorship이 되지 않는다
27줄F09-L27 @Version 출고표 27번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 creditLimit=1_000
결과·효과
관찰 상태 F09-027가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
선택하지 않은 트랙은 N-A_UNSELECTED
28줄F09-L28 private long version; 출고표 28번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 creditLimit=1_000
결과·효과
관찰 상태 F09-028가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
30줄F09-L30 protected CardAccount() {} 출고표 30번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 creditLimit=1_000
결과·효과
관찰 상태 F09-030가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
32줄F09-L32 private CardAccount(String accountKey, long creditLimit) { 출고표 32번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 조건·반복·함수의 실행 block을 연다.
입력
이전 줄의 상태와 creditLimit=1_000
결과·효과
관찰 상태 F09-032가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
UTF-8 BOM은 runtime이 거절한다
33줄F09-L33 if (accountKey == null || accountKey.isBlank()) throw new IllegalArgumentException("accountKey"); 출고표 33번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
입력
"accountKey"
결과·효과
관찰 상태 F09-033가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
선택하지 않은 트랙은 N-A_UNSELECTED
34줄F09-L34 if (creditLimit <= 0) throw new IllegalArgumentException("creditLimit"); 출고표 34번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
입력
0, "creditLimit"
결과·효과
관찰 상태 F09-034가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
35줄F09-L35 this.accountKey = accountKey; 출고표 35번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 creditLimit=1_000
결과·효과
관찰 상태 F09-035가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
36줄F09-L36 this.creditLimit = creditLimit; 출고표 36번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 creditLimit=1_000
결과·효과
관찰 상태 F09-036가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
37줄F09-L37 } 출고표 37번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
입력
이전 줄의 상태와 creditLimit=1_000
결과·효과
관찰 상태 F09-037가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference asset을 복사했다고 learner authorship이 되지 않는다
39줄F09-L39 public static CardAccount open(String accountKey, long creditLimit) { 출고표 39번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 조건·반복·함수의 실행 block을 연다.
입력
이전 줄의 상태와 creditLimit=1_000
결과·효과
관찰 상태 F09-039가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
선택하지 않은 트랙은 N-A_UNSELECTED
40줄F09-L40 return new CardAccount(accountKey, creditLimit); 출고표 40번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 creditLimit=1_000
결과·효과
관찰 상태 F09-040가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
41줄F09-L41 } 출고표 41번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
입력
이전 줄의 상태와 creditLimit=1_000
결과·효과
관찰 상태 F09-041가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
43줄F09-L43 public void hold(long amount) { 출고표 43번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 조건·반복·함수의 실행 block을 연다.
입력
이전 줄의 상태와 creditLimit=1_000
결과·효과
관찰 상태 F09-043가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference asset을 복사했다고 learner authorship이 되지 않는다
44줄F09-L44 if (amount <= 0) throw new IllegalArgumentException("amount"); 출고표 44번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
입력
0, "amount"
결과·효과
관찰 상태 F09-044가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
UTF-8 BOM은 runtime이 거절한다
45줄F09-L45 if (availableAmount() < amount) throw new IllegalStateException("INSUFFICIENT_AVAILABLE_LIMIT"); 출고표 45번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 hold 뒤 가용 한도가 700인지 관찰한다.
입력
"INSUFFICIENT_AVAILABLE_LIMIT"
결과·효과
관찰 상태 F09-045가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
선택하지 않은 트랙은 N-A_UNSELECTED
46줄F09-L46 // RED: used amount is not increased 출고표 46번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 creditLimit=1_000
결과·효과
관찰 상태 F09-046가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
47줄F09-L47 } 출고표 47번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
입력
이전 줄의 상태와 creditLimit=1_000
결과·효과
관찰 상태 F09-047가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
49줄F09-L49 public void release(long amount) { 출고표 49번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 조건·반복·함수의 실행 block을 연다.
입력
이전 줄의 상태와 creditLimit=1_000
결과·효과
관찰 상태 F09-049가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference asset을 복사했다고 learner authorship이 되지 않는다
50줄F09-L50 if (amount <= 0 || usedAmount < amount) throw new IllegalArgumentException("amount"); 출고표 50번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
입력
0, "amount"
결과·효과
관찰 상태 F09-050가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
UTF-8 BOM은 runtime이 거절한다
51줄F09-L51 usedAmount -= amount; 출고표 51번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 creditLimit=1_000
결과·효과
관찰 상태 F09-051가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
선택하지 않은 트랙은 N-A_UNSELECTED
52줄F09-L52 } 출고표 52번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
입력
이전 줄의 상태와 creditLimit=1_000
결과·효과
관찰 상태 F09-052가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
54줄F09-L54 public long availableAmount() { return creditLimit - usedAmount; } 출고표 54번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 hold 뒤 가용 한도가 700인지 관찰한다.
입력
이전 줄의 상태와 creditLimit=1_000
결과·효과
관찰 상태 F09-054가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
55줄F09-L55 public Long getId() { return id; } 출고표 55번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 creditLimit=1_000
결과·효과
관찰 상태 F09-055가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference asset을 복사했다고 learner authorship이 되지 않는다
56줄F09-L56 public String getAccountKey() { return accountKey; } 출고표 56번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 creditLimit=1_000
결과·효과
관찰 상태 F09-056가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
UTF-8 BOM은 runtime이 거절한다
57줄F09-L57 public long getUsedAmount() { return usedAmount; } 출고표 57번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 hold 뒤 사용액이 300인지 관찰한다.
입력
이전 줄의 상태와 creditLimit=1_000
결과·효과
관찰 상태 F09-057가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
선택하지 않은 트랙은 N-A_UNSELECTED
58줄F09-L58 } 출고표 58번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
입력
이전 줄의 상태와 creditLimit=1_000
결과·효과
관찰 상태 F09-058가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
05

STEP 05 / 13

원본 코드 조각

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

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

F09-C01 · 원문 1–12줄1–12줄
1–12줄 원본
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")
F09-C02 · 원문 13–24줄13–24줄
13–24줄 원본
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)
F09-C03 · 원문 25–36줄25–36줄
25–36줄 원본
    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;
F09-C04 · 원문 37–48줄37–48줄
37–48줄 원본
    }

    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
    }
F09-C05 · 원문 49–58줄49–58줄
49–58줄 원본
    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; }
}
06

STEP 06 / 13

코드 한 줄씩 한국어로 번역

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

전체 번역 46 / 46

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

원본한국어 번역
1package com.example.financialcore.card;실행 의미: CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
3import jakarta.persistence.Column;실행 의미: CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
4import jakarta.persistence.Entity;실행 의미: CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
5import jakarta.persistence.GeneratedValue;실행 의미: CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
6import jakarta.persistence.GenerationType;실행 의미: CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
7import jakarta.persistence.Id;실행 의미: CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
8import jakarta.persistence.Table;실행 의미: CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
9import jakarta.persistence.Version;실행 의미: CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
11@Entity실행 의미: CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
12@Table(name = "card_account_template")실행 의미: CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
13public 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 또는 호출 범위를 닫는다.
07

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를 서로 대체하지 않는다.

실행 순서

  1. 기본 트랙은 SECURITIES(증권)이며, 명시적 CARD 선택은 기본값을 덮어쓴다. 실제 실행 전 최종 선택 한 개를 selected-track.csv·근거·state에 같은 값으로 기록하고 서로 다른 reference/learner root를 확인한다.
  2. Prepare→VerifyStarter→RecordRed→VerifySolution→RecordGreen→Cumulative→Review 순서를 지킨다.
  3. test를 소유한 세 phase에서만 native exit와 exact JUnit XML 수치를 판정한다.
  4. 다음 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 증가 누락히토리 → 니지카 → 료 → 키타
  1. 히토리

    usedAmount=0가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 hold가 사용액을 늘리지 않아 같은 한도를 반복 승인할 수 있는 의도한 Red 반례를 읽는다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘UTF-8 BOM은 runtime이 거절한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 usedAmount=0와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

08

STEP 08 / 13

실제 값 따라가기

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

순서들어온 값코드가 하는 일나온 값·상태경계
입력creditLimit=1_000source 계약에 대입F09 실행/설명 시작 상태reference asset을 복사했다고 learner authorship이 되지 않는다
검증usedAmount=0expected와 actual 또는 형식 대조통과 또는 첫 mismatchUTF-8 BOM은 runtime이 거절한다
증거RED commentmarker·hash·row를 같은 run에 연결범위가 적힌 evidence 후보이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
실제 값 — CARD starter CardAccount — usedAmount 증가 누락히토리 → 니지카 → 료 → 키타
  1. 히토리

    hold(300)가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 hold가 사용액을 늘리지 않아 같은 한도를 반복 승인할 수 있는 의도한 Red 반례를 읽는다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘선택하지 않은 트랙은 N-A_UNSELECTED’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 hold(300)와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

09

STEP 09 / 13

Gradle·JUnit XML·PowerShell·SQL 내부에서 벌어지는 일

세 test phase, XML bytes archive, Review, 별도 Q41, USER_ATTESTED sealed 결과의 owner와 증명 범위를 구분합니다.

source/contract

CardAccount.java bytes와 track·phase·hash 계약을 읽는다.

SECURITIES 기본 선택과 파일 존재·phase 이름만으로 runtime Green을 주장할 수 없다. 실제 selected-track evidence와 실행 결과는 별도다.
execution/evidence

RecordRed·RecordGreen·Cumulative에서만 native exit와 exact JUnit XML을 만든다.

reference asset을 복사했다고 learner authorship이 되지 않는다
retention/review

XML bytes를 고유 파일로 보존하고 history hash와 묶은 뒤, Review는 기존 CumulativeGreen만 인용한다. Q41은 별도 PostgreSQL evidence, sealed official status는 user-attested evidence로 남긴다.

이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
첫 실패 경계 — CARD starter CardAccount — usedAmount 증가 누락히토리 → 니지카 → 료 → 키타
  1. 히토리

    used remains 0가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 hold가 사용액을 늘리지 않아 같은 한도를 반복 승인할 수 있는 의도한 Red 반례를 읽는다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘reference와 learner root는 서로 달라야 한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 used remains 0와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

10

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이 생기지 않는다.

11

STEP 11 / 13

이 코드가 보장하지 않는 것

선택 미결정·10_000 finalState·XML 보존·Review/Q41/sealed official truth처럼 이 코드가 책임지지 않는 일을 분리합니다.

증명 범위

reference asset을 복사했다고 learner authorship이 되지 않는다

이 책임을 맡는 곳: runtime Gate
증명 범위

UTF-8 BOM은 runtime이 거절한다

이 책임을 맡는 곳: external/human review
증명 범위

선택하지 않은 트랙은 N-A_UNSELECTED

이 책임을 맡는 곳: release manifest
증명 범위

reference와 learner root는 서로 달라야 한다

이 책임을 맡는 곳: 운영 환경
증명하지 않는 범위 — CARD starter CardAccount — usedAmount 증가 누락히토리 → 니지카 → 료 → 키타
  1. 히토리

    RED comment가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 hold가 사용액을 늘리지 않아 같은 한도를 반복 승인할 수 있는 의도한 Red 반례를 읽는다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 RED comment와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

12

STEP 12 / 13

직접 다시 써보기

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

1단계 · 뜻부터 복원

  • hold가 사용액을 늘리지 않아 같은 한도를 반복 승인할 수 있는 의도한 Red 반례를 읽는다.
  • 핵심 값은 creditLimit=1_000, usedAmount=0, hold(300), used remains 0, RED comment다.

2단계 · 코드 조각 재조립

  1. 1. CardAccount.java의 다음 검증 또는 설명 단계를 구성한다
  2. 3. CardAccount.java의 다음 검증 또는 설명 단계를 구성한다
  3. 4. CardAccount.java의 다음 검증 또는 설명 단계를 구성한다
  4. 5. CardAccount.java의 다음 검증 또는 설명 단계를 구성한다
  5. 6. CardAccount.java의 다음 검증 또는 설명 단계를 구성한다
  6. 7. CardAccount.java의 다음 검증 또는 설명 단계를 구성한다
  7. 8. CardAccount.java의 다음 검증 또는 설명 단계를 구성한다
  8. 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 책임을 설명할 수 있나?
13

STEP 13 / 13

전체 원본 source

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

원문 정본 전체 source 확인하기
PDF 전문 정본 · learner starter Javatrack_learning_stages/card/w25/starter/src/main/java/com/example/financialcore/card/CardAccount.javaSHA-256 cc62b9dd28d90f23ada49f810436ed04ce2d604e6b902d72183a7887bbc07ea2
CARD starter CardAccount — usedAmount 증가 누락 전체
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; }
}
10

D2 VerifyStarter — starter canonical/raw hash만 검증

illustrative/powershell/W25-D2-verify-starter.ps1

학습용 예시 · W25 phase wrapper · 정본 답안 아님 · 로컬 미실행 · 학습용 예시 · 정본 답안 아님 · NOT_RUN · W25-F10
25줄 연결25줄 번역3 chunks
01

STEP 01 / 13

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

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

오늘의 한 문장

Prepared 이후 learner가 직접 입력한 선택 트랙 starter hash와 소유권을 확인하되 새 test 실행이 없음을 확인한다.

  1. Prepared은 어느 source와 실제 결과에서 확인해야 할까?
  2. 첫 실패를 만드는 조건과 fail-closed 지점은 어디일까?
  3. 왜 ‘compile 가능성과 Red XML은 아직 증명되지 않는다’를 별도 경계로 남겨야 할까?
이 파일에서 끝까지 다시 쓰는 값PreparedStarterVerifiedauthoredTargetcanonical/raw SHA-256runtime_claim=false
왜 필요한가 — raw hash만 검증히토리 → 니지카 → 료 → 키타
  1. 히토리

    Prepared가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 Prepared 이후 learner가 직접 입력한 선택 트랙 starter hash와 소유권을 확인하되 새 test 실행이 없음을 확인한다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘compile 가능성과 Red XML은 아직 증명되지 않는다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 Prepared와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

02

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 확인을 대신하지 않는다.

03

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을 실행하지 않았다
04

STEP 04 / 13

비유 ↔ 코드 전체 연결표

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

단어 몇 개만 뽑은 표가 아닙니다.학습용 예시 · W25 phase wrapper · 정본 답안 아님 · 로컬 미실행에서 비어 있지 않은 모든 줄을 원본 줄 번호 그대로 연결했습니다.25 / 25 연결
정확한 원본 줄STARRY 비유실제 뜻·입력·결과·한계
1줄F10-L01 # W25 PDF p8-p17의 VerifyStarter 흐름을 정리한 학습용 예시다. 출고표 1번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 starter canonical/raw hash만 검증하고 Gradle은 실행하지 않는 phase다.
입력
이전 줄의 상태와 Prepared
결과·효과
관찰 상태 F10-001가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
compile 가능성과 Red XML은 아직 증명되지 않는다
2줄F10-L02 # 이 phase는 starter bytes/hash와 leak 경계를 검증하지만 Gradle test를 실행하지 않는다. 출고표 2번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다.
입력
이전 줄의 상태와 Prepared
결과·효과
관찰 상태 F10-002가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
README BOM 허용 문구보다 runtime 무 BOM 규칙이 우선한다
3줄F10-L03 $ErrorActionPreference = 'Stop' 출고표 3번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 PowerShell 오류를 계속 진행하지 않고 중단시키는 기본 정책을 둔다.
입력
$ErrorActionPreference, 'Stop'
결과·효과
관찰 상태 F10-003가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
4줄F10-L04 $ReferenceRoot = (Resolve-Path -LiteralPath $env:FINANCIAL_IT_REFERENCE_ROOT).Path 출고표 4번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 입력 경로를 실제 절대 경로로 확인한다.
입력
$ReferenceRoot, $env
결과·효과
관찰 상태 F10-004가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
5줄F10-L05 $LearnerRoot = (Resolve-Path -LiteralPath $env:FINANCIAL_IT_LEARNER_ROOT).Path 출고표 5번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 입력 경로를 실제 절대 경로로 확인한다.
입력
$LearnerRoot, $env
결과·효과
관찰 상태 F10-005가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
6줄F10-L06 if ([string]::Equals($ReferenceRoot, $LearnerRoot, [StringComparison]::OrdinalIgnoreCase)) { 출고표 6번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 조건·반복·함수의 실행 block을 연다.
입력
$ReferenceRoot, $LearnerRoot
결과·효과
관찰 상태 F10-006가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
compile 가능성과 Red XML은 아직 증명되지 않는다
7줄F10-L07 throw 'reference and learner roots must be different' 출고표 7번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
입력
이전 줄의 상태와 Prepared
결과·효과
관찰 상태 F10-007가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
README BOM 허용 문구보다 runtime 무 BOM 규칙이 우선한다
8줄F10-L08 } 출고표 8번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
입력
이전 줄의 상태와 Prepared
결과·효과
관찰 상태 F10-008가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
9줄F10-L09 $Before = Get-Content -Raw -LiteralPath (Join-Path $LearnerRoot '.track-learning-stage.json') | ConvertFrom-Json 출고표 9번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 JSON text를 필드로 접근 가능한 PowerShell object로 바꾼다.
입력
$Before, $LearnerRoot, '.track-learning-stage.json'
결과·효과
관찰 상태 F10-009가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
10줄F10-L10 if ($Before.week -ne 25 -or $Before.phase -cne 'Prepared') { throw 'VerifyStarter requires Prepared' } 출고표 10번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 starter canonical/raw hash만 검증하고 Gradle은 실행하지 않는 phase다.
입력
$Before, 25, $Before
결과·효과
관찰 상태 F10-010가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
12줄F10-L12 $Runner = Join-Path $ReferenceRoot 'scripts\apply-track-learning-stage.ps1' 출고표 12번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
입력
$Runner, $ReferenceRoot, 'scripts\apply-track-learning-stage.ps1'
결과·효과
관찰 상태 F10-012가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
README BOM 허용 문구보다 runtime 무 BOM 규칙이 우선한다
13줄F10-L13 & powershell.exe -NoProfile -ExecutionPolicy Bypass -File $Runner ` 출고표 13번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 W25-D2-verify-starter.ps1의 다음 검증 또는 설명 단계를 구성한다.
입력
$Runner
결과·효과
관찰 상태 F10-013가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
14줄F10-L14 -ReferenceRoot $ReferenceRoot -LearnerRoot $LearnerRoot -Week 25 -Phase VerifyStarter -TimeoutSeconds 1200 출고표 14번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 starter canonical/raw hash만 검증하고 Gradle은 실행하지 않는 phase다.
입력
$ReferenceRoot, $LearnerRoot, 25
결과·효과
관찰 상태 F10-014가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
15줄F10-L15 if ($LASTEXITCODE -ne 0) { throw "W25 VerifyStarter native exit=$LASTEXITCODE" } 출고표 15번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 starter canonical/raw hash만 검증하고 Gradle은 실행하지 않는 phase다.
입력
$LASTEXITCODE, 0, $LASTEXITCODE
결과·효과
관찰 상태 F10-015가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
17줄F10-L17 $StatePath = Join-Path $LearnerRoot '.track-learning-stage.json' 출고표 17번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
입력
$StatePath, $LearnerRoot, '.track-learning-stage.json'
결과·효과
관찰 상태 F10-017가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
README BOM 허용 문구보다 runtime 무 BOM 규칙이 우선한다
18줄F10-L18 $State = Get-Content -Raw -LiteralPath $StatePath | ConvertFrom-Json 출고표 18번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 JSON text를 필드로 접근 가능한 PowerShell object로 바꾼다.
입력
$State, $StatePath
결과·효과
관찰 상태 F10-018가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
19줄F10-L19 $Entry = @($State.history)[-1] 출고표 19번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
입력
$Entry, $State, 1
결과·효과
관찰 상태 F10-019가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
20줄F10-L20 if ($State.phase -cne 'StarterVerified' -or $Entry.phase -cne 'VerifyStarter') { 출고표 20번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 starter canonical/raw hash만 검증하고 Gradle은 실행하지 않는 phase다.
입력
$State, 'StarterVerified', $Entry
결과·효과
관찰 상태 F10-020가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
21줄F10-L21 throw 'W25 VerifyStarter state mismatch' 출고표 21번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 starter canonical/raw hash만 검증하고 Gradle은 실행하지 않는 phase다.
입력
'W25 VerifyStarter state mismatch'
결과·효과
관찰 상태 F10-021가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
compile 가능성과 Red XML은 아직 증명되지 않는다
22줄F10-L22 } 출고표 22번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
입력
이전 줄의 상태와 Prepared
결과·효과
관찰 상태 F10-022가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
README BOM 허용 문구보다 runtime 무 BOM 규칙이 우선한다
23줄F10-L23 if ($null -eq $Entry.authoredTarget -or $null -ne $Entry.execution) { 출고표 23번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 학습자가 직접 소유하는 main Java 경로와 starter/solution hash를 묶는다.
입력
$null, $Entry, $null
결과·효과
관찰 상태 F10-023가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
24줄F10-L24 throw 'VerifyStarter must record authoredTarget without execution evidence' 출고표 24번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 학습자가 직접 소유하는 main Java 경로와 starter/solution hash를 묶는다.
입력
이전 줄의 상태와 Prepared
결과·효과
관찰 상태 F10-024가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
25줄F10-L25 } 출고표 25번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
입력
이전 줄의 상태와 Prepared
결과·효과
관찰 상태 F10-025가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
26줄F10-L26 $Hash = (Get-FileHash -LiteralPath $StatePath -Algorithm SHA256).Hash.ToLowerInvariant() 출고표 26번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 현재 bytes를 64자리 digest로 evidence에 결박한다.
입력
$Hash, $StatePath
결과·효과
관찰 상태 F10-026가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
compile 가능성과 Red XML은 아직 증명되지 않는다
27줄F10-L27 "W25_STARTER_HASH_VERIFIED phase=StarterVerified runtime_claim=false state_sha256=$Hash" 출고표 27번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 현재 bytes를 64자리 digest로 evidence에 결박한다.
입력
$Hash
결과·효과
관찰 상태 F10-027가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
README BOM 허용 문구보다 runtime 무 BOM 규칙이 우선한다
05

STEP 05 / 13

원본 코드 조각

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

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

F10-C01 · 원문 1–12줄1–12줄
1–12줄 원본
# 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'
F10-C02 · 원문 13–24줄13–24줄
13–24줄 원본
& 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'
F10-C03 · 원문 25–27줄25–27줄
25–27줄 원본
}
$Hash = (Get-FileHash -LiteralPath $StatePath -Algorithm SHA256).Hash.ToLowerInvariant()
"W25_STARTER_HASH_VERIFIED phase=StarterVerified runtime_claim=false state_sha256=$Hash"
06

STEP 06 / 13

코드 한 줄씩 한국어로 번역

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

전체 번역 25 / 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실행 의미: 입력 경로를 실제 절대 경로로 확인한다.
6if ([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로 바꾼다.
10if ($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다.
15if ($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 변수에 저장한다.
20if ($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 또는 호출 범위를 닫는다.
23if ($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에 결박한다.
07

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를 서로 대체하지 않는다.

실행 순서

  1. 기본 트랙은 SECURITIES(증권)이며, 명시적 CARD 선택은 기본값을 덮어쓴다. 실제 실행 전 최종 선택 한 개를 selected-track.csv·근거·state에 같은 값으로 기록하고 서로 다른 reference/learner root를 확인한다.
  2. Prepare→VerifyStarter→RecordRed→VerifySolution→RecordGreen→Cumulative→Review 순서를 지킨다.
  3. test를 소유한 세 phase에서만 native exit와 exact JUnit XML 수치를 판정한다.
  4. 다음 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만 검증히토리 → 니지카 → 료 → 키타
  1. 히토리

    StarterVerified가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 Prepared 이후 learner가 직접 입력한 선택 트랙 starter hash와 소유권을 확인하되 새 test 실행이 없음을 확인한다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘README BOM 허용 문구보다 runtime 무 BOM 규칙이 우선한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 StarterVerified와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

08

STEP 08 / 13

실제 값 따라가기

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

순서들어온 값코드가 하는 일나온 값·상태경계
입력Preparedsource 계약에 대입F10 실행/설명 시작 상태compile 가능성과 Red XML은 아직 증명되지 않는다
검증StarterVerifiedexpected와 actual 또는 형식 대조통과 또는 첫 mismatchREADME BOM 허용 문구보다 runtime 무 BOM 규칙이 우선한다
증거runtime_claim=falsemarker·hash·row를 같은 run에 연결범위가 적힌 evidence 후보이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
실제 값 — raw hash만 검증히토리 → 니지카 → 료 → 키타
  1. 히토리

    authoredTarget가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 Prepared 이후 learner가 직접 입력한 선택 트랙 starter hash와 소유권을 확인하되 새 test 실행이 없음을 확인한다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘reference와 learner root는 서로 달라야 한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 authoredTarget와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

09

STEP 09 / 13

Gradle·JUnit XML·PowerShell·SQL 내부에서 벌어지는 일

세 test phase, XML bytes archive, Review, 별도 Q41, USER_ATTESTED sealed 결과의 owner와 증명 범위를 구분합니다.

source/contract

W25-D2-verify-starter.ps1 bytes와 track·phase·hash 계약을 읽는다.

SECURITIES 기본 선택과 파일 존재·phase 이름만으로 runtime Green을 주장할 수 없다. 실제 selected-track evidence와 실행 결과는 별도다.
execution/evidence

RecordRed·RecordGreen·Cumulative에서만 native exit와 exact JUnit XML을 만든다.

compile 가능성과 Red XML은 아직 증명되지 않는다
retention/review

XML bytes를 고유 파일로 보존하고 history hash와 묶은 뒤, Review는 기존 CumulativeGreen만 인용한다. Q41은 별도 PostgreSQL evidence, sealed official status는 user-attested evidence로 남긴다.

이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
첫 실패 경계 — raw hash만 검증히토리 → 니지카 → 료 → 키타
  1. 히토리

    canonical/raw SHA-256가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 Prepared 이후 learner가 직접 입력한 선택 트랙 starter hash와 소유권을 확인하되 새 test 실행이 없음을 확인한다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 canonical/raw SHA-256와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

10

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이 생기지 않는다.

11

STEP 11 / 13

이 코드가 보장하지 않는 것

선택 미결정·10_000 finalState·XML 보존·Review/Q41/sealed official truth처럼 이 코드가 책임지지 않는 일을 분리합니다.

증명 범위

compile 가능성과 Red XML은 아직 증명되지 않는다

이 책임을 맡는 곳: runtime Gate
증명 범위

README BOM 허용 문구보다 runtime 무 BOM 규칙이 우선한다

이 책임을 맡는 곳: external/human review
증명 범위

reference와 learner root는 서로 달라야 한다

이 책임을 맡는 곳: release manifest
증명 범위

기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다

이 책임을 맡는 곳: 운영 환경
증명하지 않는 범위 — raw hash만 검증히토리 → 니지카 → 료 → 키타
  1. 히토리

    runtime_claim=false가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 Prepared 이후 learner가 직접 입력한 선택 트랙 starter hash와 소유권을 확인하되 새 test 실행이 없음을 확인한다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 runtime_claim=false와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

12

STEP 12 / 13

직접 다시 써보기

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

1단계 · 뜻부터 복원

  • Prepared 이후 learner가 직접 입력한 선택 트랙 starter hash와 소유권을 확인하되 새 test 실행이 없음을 확인한다.
  • 핵심 값은 Prepared, StarterVerified, authoredTarget, canonical/raw SHA-256, runtime_claim=false다.

2단계 · 코드 조각 재조립

  1. 1. starter canonical/raw hash만 검증하고 Gradle은 실행하지 않는 phase다
  2. 2. 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다
  3. 3. PowerShell 오류를 계속 진행하지 않고 중단시키는 기본 정책을 둔다
  4. 4. 입력 경로를 실제 절대 경로로 확인한다
  5. 5. 입력 경로를 실제 절대 경로로 확인한다
  6. 6. 조건·반복·함수의 실행 block을 연다
  7. 7. 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다
  8. 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 책임을 설명할 수 있나?
13

STEP 13 / 13

전체 원본 source

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

학습용 예시 전체 확인하기 · 정본 답안 아님 · NOT_RUN
학습용 예시 · W25 phase wrapper · 정본 답안 아님 · 로컬 미실행illustrative/powershell/W25-D2-verify-starter.ps1SHA-256 a4e5cdb24432fc9e3864069db8718661ad93144bff45c2717fa45f4b6dd1057f
D2 VerifyStarter — starter canonical/raw hash만 검증 전체
# 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"
11

D3 RecordRed — exact one-test Red와 XML archive

illustrative/powershell/W25-D3-record-red.ps1

학습용 예시 · W25 phase wrapper · 정본 답안 아님 · 로컬 미실행 · 학습용 예시 · 정본 답안 아님 · NOT_RUN · W25-F11
34줄 연결34줄 번역3 chunks
01

STEP 01 / 13

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

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

오늘의 한 문장

native nonzero·tests=1·failure+error=1·skip=0·exact method·redMarker를 함께 확인하고 다음 cleanTest 전에 XML bytes를 보존한다.

  1. LearnerRed은 어느 source와 실제 결과에서 확인해야 할까?
  2. 첫 실패를 만드는 조건과 fail-closed 지점은 어디일까?
  3. 왜 ‘compile error는 XML과 marker가 없어 올바른 Red가 아니다’를 별도 경계로 남겨야 할까?
이 파일에서 끝까지 다시 쓰는 값LearnerRednativeExit≠0tests=1failures+errors=1red-exact.xml
왜 필요한가 — D3 RecordRed — exact one-test Red와 XML archive히토리 → 니지카 → 료 → 키타
  1. 히토리

    LearnerRed가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 native nonzero·tests=1·failure+error=1·skip=0·exact method·redMarker를 함께 확인하고 다음 cleanTest 전에 XML bytes를 보존한다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘compile error는 XML과 marker가 없어 올바른 Red가 아니다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 LearnerRed와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

02

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 확인을 대신하지 않는다.

03

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을 실행하지 않았다
04

STEP 04 / 13

비유 ↔ 코드 전체 연결표

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

단어 몇 개만 뽑은 표가 아닙니다.학습용 예시 · W25 phase wrapper · 정본 답안 아님 · 로컬 미실행에서 비어 있지 않은 모든 줄을 원본 줄 번호 그대로 연결했습니다.34 / 34 연결
정확한 원본 줄STARRY 비유실제 뜻·입력·결과·한계
1줄F11-L01 # W25 PDF p18-p22의 exact one-test Red 흐름을 정리한 학습용 예시다. 출고표 1번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다.
입력
이전 줄의 상태와 LearnerRed
결과·효과
관찰 상태 F11-001가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
compile error는 XML과 marker가 없어 올바른 Red가 아니다
2줄F11-L02 # native nonzero exit, 단일 JUnit 실패, 선택 트랙 redMarker가 함께 있어야 Red다. 출고표 2번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다.
입력
이전 줄의 상태와 LearnerRed
결과·효과
관찰 상태 F11-002가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
history xmlSha256은 XML bytes 보관을 대신하지 않는다
3줄F11-L03 $ErrorActionPreference = 'Stop' 출고표 3번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 PowerShell 오류를 계속 진행하지 않고 중단시키는 기본 정책을 둔다.
입력
$ErrorActionPreference, 'Stop'
결과·효과
관찰 상태 F11-003가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
4줄F11-L04 $ReferenceRoot = (Resolve-Path -LiteralPath $env:FINANCIAL_IT_REFERENCE_ROOT).Path 출고표 4번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 입력 경로를 실제 절대 경로로 확인한다.
입력
$ReferenceRoot, $env
결과·효과
관찰 상태 F11-004가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
5줄F11-L05 $LearnerRoot = (Resolve-Path -LiteralPath $env:FINANCIAL_IT_LEARNER_ROOT).Path 출고표 5번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 입력 경로를 실제 절대 경로로 확인한다.
입력
$LearnerRoot, $env
결과·효과
관찰 상태 F11-005가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
6줄F11-L06 if ([string]::Equals($ReferenceRoot, $LearnerRoot, [StringComparison]::OrdinalIgnoreCase)) { 출고표 6번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 조건·반복·함수의 실행 block을 연다.
입력
$ReferenceRoot, $LearnerRoot
결과·효과
관찰 상태 F11-006가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
compile error는 XML과 marker가 없어 올바른 Red가 아니다
7줄F11-L07 throw 'reference and learner roots must be different' 출고표 7번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
입력
이전 줄의 상태와 LearnerRed
결과·효과
관찰 상태 F11-007가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
history xmlSha256은 XML bytes 보관을 대신하지 않는다
8줄F11-L08 } 출고표 8번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
입력
이전 줄의 상태와 LearnerRed
결과·효과
관찰 상태 F11-008가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
10줄F11-L10 $Verifier = Join-Path $ReferenceRoot 'scripts\verify-track-learner-proof.ps1' 출고표 10번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
입력
$Verifier, $ReferenceRoot, 'scripts\verify-track-learner-proof.ps1'
결과·효과
관찰 상태 F11-010가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
11줄F11-L11 & powershell.exe -NoProfile -ExecutionPolicy Bypass -File $Verifier ` 출고표 11번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 W25-D3-record-red.ps1의 다음 검증 또는 설명 단계를 구성한다.
입력
$Verifier
결과·효과
관찰 상태 F11-011가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
compile error는 XML과 marker가 없어 올바른 Red가 아니다
12줄F11-L12 -ReferenceRoot $ReferenceRoot -LearnerRoot $LearnerRoot -Week 25 -Phase RecordRed -TimeoutSeconds 1200 출고표 12번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 선택 트랙 test 하나의 의도한 실패와 Red marker를 기록하는 phase다.
입력
$ReferenceRoot, $LearnerRoot, 25
결과·효과
관찰 상태 F11-012가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
history xmlSha256은 XML bytes 보관을 대신하지 않는다
13줄F11-L13 if ($LASTEXITCODE -ne 0) { throw "W25 RecordRed wrapper exit=$LASTEXITCODE" } 출고표 13번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 선택 트랙 test 하나의 의도한 실패와 Red marker를 기록하는 phase다.
입력
$LASTEXITCODE, 0, "W25 RecordRed wrapper exit=$LASTEXITCODE"
결과·효과
관찰 상태 F11-013가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
15줄F11-L15 $State = Get-Content -Raw -LiteralPath (Join-Path $LearnerRoot '.track-learning-stage.json') | ConvertFrom-Json 출고표 15번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 JSON text를 필드로 접근 가능한 PowerShell object로 바꾼다.
입력
$State, $LearnerRoot, '.track-learning-stage.json'
결과·효과
관찰 상태 F11-015가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
16줄F11-L16 $Entry = @($State.history)[-1] 출고표 16번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
입력
$Entry, $State, 1
결과·효과
관찰 상태 F11-016가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
compile error는 XML과 marker가 없어 올바른 Red가 아니다
17줄F11-L17 $Suites = @($Entry.execution.suites) 출고표 17번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
입력
$Suites, $Entry
결과·효과
관찰 상태 F11-017가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
history xmlSha256은 XML bytes 보관을 대신하지 않는다
18줄F11-L18 if ($State.phase -cne 'LearnerRed' -or $Entry.execution.mode -cne 'Red') { throw 'LearnerRed state mismatch' } 출고표 18번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
입력
$State, 'LearnerRed', $Entry
결과·효과
관찰 상태 F11-018가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
19줄F11-L19 if ($Entry.execution.nativeExit -eq 0 -or $Suites.Count -ne 1) { throw 'Red must have native nonzero exit and one suite' } 출고표 19번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
입력
$Entry, 0, $Suites
결과·효과
관찰 상태 F11-019가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
20줄F11-L20 $Suite = $Suites[0] 출고표 20번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
입력
$Suite, $Suites, 0
결과·효과
관찰 상태 F11-020가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
21줄F11-L21 if ($Suite.tests -ne 1 -or ($Suite.failures + $Suite.errors) -ne 1 -or $Suite.skipped -ne 0) { 출고표 21번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 조건·반복·함수의 실행 block을 연다.
입력
$Suite, 1, $Suite
결과·효과
관찰 상태 F11-021가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
compile error는 XML과 marker가 없어 올바른 Red가 아니다
22줄F11-L22 throw 'Red XML must be tests=1, failures+errors=1, skipped=0' 출고표 22번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
입력
1, 1, 0
결과·효과
관찰 상태 F11-022가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
history xmlSha256은 XML bytes 보관을 대신하지 않는다
23줄F11-L23 } 출고표 23번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
입력
이전 줄의 상태와 LearnerRed
결과·효과
관찰 상태 F11-023가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
24줄F11-L24 $Marker = if ($State.track -ceq 'SECURITIES') { 'W25_SECURITIES_RED_EXPECTED' } else { 'W25_CARD_RED_EXPECTED' } 출고표 24번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
입력
$Marker, $State, 'SECURITIES'
결과·효과
관찰 상태 F11-024가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
25줄F11-L25 $Log = Get-Content -Raw -LiteralPath (Join-Path $LearnerRoot $Entry.execution.log) 출고표 25번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
입력
$Log, $LearnerRoot, $Entry
결과·효과
관찰 상태 F11-025가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
26줄F11-L26 if ($Log -cnotmatch [regex]::Escape($Marker)) { throw "exact Red marker missing: $Marker" } 출고표 26번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
입력
$Log, $Marker, "exact Red marker missing: $Marker"
결과·효과
관찰 상태 F11-026가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
compile error는 XML과 marker가 없어 올바른 Red가 아니다
27줄F11-L27 $Xml = Join-Path $LearnerRoot ("build\test-results\test\TEST-{0}.xml" -f $Suite.selector) 출고표 27번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
입력
$Xml, $LearnerRoot, "build\test-results\test\TEST-{0}.xml"
결과·효과
관찰 상태 F11-027가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
history xmlSha256은 XML bytes 보관을 대신하지 않는다
28줄F11-L28 $ArchiveDir = Join-Path $LearnerRoot ("evidence\w25\{0}" -f $State.track.ToLowerInvariant()) 출고표 28번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
입력
$ArchiveDir, $LearnerRoot, "evidence\w25\{0}"
결과·효과
관찰 상태 F11-028가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
29줄F11-L29 New-Item -ItemType Directory -Force -Path $ArchiveDir | Out-Null 출고표 29번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 Markdown 표 또는 PowerShell pipeline에서 값을 열이나 다음 명령으로 연결한다.
입력
$ArchiveDir
결과·효과
관찰 상태 F11-029가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
30줄F11-L30 $Archive = Join-Path $ArchiveDir 'red-exact.xml' 출고표 30번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 덮어쓰기 전에 Red JUnit XML bytes를 고유 evidence 경로로 보존한다.
입력
$Archive, $ArchiveDir, 'red-exact.xml'
결과·효과
관찰 상태 F11-030가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
31줄F11-L31 $Tmp = "$Archive.tmp" 출고표 31번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
입력
$Tmp, "$Archive.tmp"
결과·효과
관찰 상태 F11-031가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
compile error는 XML과 marker가 없어 올바른 Red가 아니다
32줄F11-L32 Copy-Item -LiteralPath $Xml -Destination $Tmp -Force 출고표 32번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 W25-D3-record-red.ps1의 다음 검증 또는 설명 단계를 구성한다.
입력
$Xml, $Tmp
결과·효과
관찰 상태 F11-032가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
history xmlSha256은 XML bytes 보관을 대신하지 않는다
33줄F11-L33 $ArchiveHash = (Get-FileHash -LiteralPath $Tmp -Algorithm SHA256).Hash.ToLowerInvariant() 출고표 33번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 현재 bytes를 64자리 digest로 evidence에 결박한다.
입력
$ArchiveHash, $Tmp
결과·효과
관찰 상태 F11-033가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
34줄F11-L34 if ($ArchiveHash -cne $Suite.xmlSha256) { throw 'archived Red XML hash differs from runtime history' } 출고표 34번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 현재 bytes를 64자리 digest로 evidence에 결박한다.
입력
$ArchiveHash, $Suite
결과·효과
관찰 상태 F11-034가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
35줄F11-L35 Move-Item -LiteralPath $Tmp -Destination $Archive -Force 출고표 35번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 W25-D3-record-red.ps1의 다음 검증 또는 설명 단계를 구성한다.
입력
$Tmp, $Archive
결과·효과
관찰 상태 F11-035가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
36줄F11-L36 "W25_EXACT_RED_VERIFIED track=$($State.track) tests=1 failures_or_errors=1 native_exit=$($Entry.execution.nativeExit) archived_xml_sha256=$ArchiveHash" 출고표 36번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 현재 bytes를 64자리 digest로 evidence에 결박한다.
입력
$State, 1, 1
결과·효과
관찰 상태 F11-036가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
compile error는 XML과 marker가 없어 올바른 Red가 아니다
05

STEP 05 / 13

원본 코드 조각

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

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

F11-C01 · 원문 1–12줄1–12줄
1–12줄 원본
# 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
F11-C02 · 원문 13–24줄13–24줄
13–24줄 원본
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' }
F11-C03 · 원문 25–36줄25–36줄
25–36줄 원본
$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"
06

STEP 06 / 13

코드 한 줄씩 한국어로 번역

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

전체 번역 34 / 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실행 의미: 입력 경로를 실제 절대 경로로 확인한다.
6if ([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다.
13if ($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 변수에 저장한다.
18if ($State.phase -cne 'LearnerRed' -or $Entry.execution.mode -cne 'Red') { throw 'LearnerRed state mismatch' }실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
19if ($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 변수에 저장한다.
21if ($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 변수에 저장한다.
26if ($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 변수에 저장한다.
29New-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 변수에 저장한다.
32Copy-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에 결박한다.
34if ($ArchiveHash -cne $Suite.xmlSha256) { throw 'archived Red XML hash differs from runtime history' }실행 의미: 현재 bytes를 64자리 digest로 evidence에 결박한다.
35Move-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에 결박한다.
07

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를 서로 대체하지 않는다.

실행 순서

  1. 기본 트랙은 SECURITIES(증권)이며, 명시적 CARD 선택은 기본값을 덮어쓴다. 실제 실행 전 최종 선택 한 개를 selected-track.csv·근거·state에 같은 값으로 기록하고 서로 다른 reference/learner root를 확인한다.
  2. Prepare→VerifyStarter→RecordRed→VerifySolution→RecordGreen→Cumulative→Review 순서를 지킨다.
  3. test를 소유한 세 phase에서만 native exit와 exact JUnit XML 수치를 판정한다.
  4. 다음 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히토리 → 니지카 → 료 → 키타
  1. 히토리

    nativeExit≠0가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 native nonzero·tests=1·failure+error=1·skip=0·exact method·redMarker를 함께 확인하고 다음 cleanTest 전에 XML bytes를 보존한다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘history xmlSha256은 XML bytes 보관을 대신하지 않는다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 nativeExit≠0와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

08

STEP 08 / 13

실제 값 따라가기

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

순서들어온 값코드가 하는 일나온 값·상태경계
입력LearnerRedsource 계약에 대입F11 실행/설명 시작 상태compile error는 XML과 marker가 없어 올바른 Red가 아니다
검증nativeExit≠0expected와 actual 또는 형식 대조통과 또는 첫 mismatchhistory xmlSha256은 XML bytes 보관을 대신하지 않는다
증거red-exact.xmlmarker·hash·row를 같은 run에 연결범위가 적힌 evidence 후보이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
실제 값 — D3 RecordRed — exact one-test Red와 XML archive히토리 → 니지카 → 료 → 키타
  1. 히토리

    tests=1가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 native nonzero·tests=1·failure+error=1·skip=0·exact method·redMarker를 함께 확인하고 다음 cleanTest 전에 XML bytes를 보존한다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘reference와 learner root는 서로 달라야 한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 tests=1와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

09

STEP 09 / 13

Gradle·JUnit XML·PowerShell·SQL 내부에서 벌어지는 일

세 test phase, XML bytes archive, Review, 별도 Q41, USER_ATTESTED sealed 결과의 owner와 증명 범위를 구분합니다.

source/contract

W25-D3-record-red.ps1 bytes와 track·phase·hash 계약을 읽는다.

SECURITIES 기본 선택과 파일 존재·phase 이름만으로 runtime Green을 주장할 수 없다. 실제 selected-track evidence와 실행 결과는 별도다.
execution/evidence

RecordRed·RecordGreen·Cumulative에서만 native exit와 exact JUnit XML을 만든다.

compile error는 XML과 marker가 없어 올바른 Red가 아니다
retention/review

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히토리 → 니지카 → 료 → 키타
  1. 히토리

    failures+errors=1가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 native nonzero·tests=1·failure+error=1·skip=0·exact method·redMarker를 함께 확인하고 다음 cleanTest 전에 XML bytes를 보존한다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 failures+errors=1와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

10

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이 생기지 않는다.

11

STEP 11 / 13

이 코드가 보장하지 않는 것

선택 미결정·10_000 finalState·XML 보존·Review/Q41/sealed official truth처럼 이 코드가 책임지지 않는 일을 분리합니다.

증명 범위

compile error는 XML과 marker가 없어 올바른 Red가 아니다

이 책임을 맡는 곳: runtime Gate
증명 범위

history xmlSha256은 XML bytes 보관을 대신하지 않는다

이 책임을 맡는 곳: external/human review
증명 범위

reference와 learner root는 서로 달라야 한다

이 책임을 맡는 곳: release manifest
증명 범위

기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다

이 책임을 맡는 곳: 운영 환경
증명하지 않는 범위 — D3 RecordRed — exact one-test Red와 XML archive히토리 → 니지카 → 료 → 키타
  1. 히토리

    red-exact.xml가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 native nonzero·tests=1·failure+error=1·skip=0·exact method·redMarker를 함께 확인하고 다음 cleanTest 전에 XML bytes를 보존한다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 red-exact.xml와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

12

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. 1. 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다
  2. 2. 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다
  3. 3. PowerShell 오류를 계속 진행하지 않고 중단시키는 기본 정책을 둔다
  4. 4. 입력 경로를 실제 절대 경로로 확인한다
  5. 5. 입력 경로를 실제 절대 경로로 확인한다
  6. 6. 조건·반복·함수의 실행 block을 연다
  7. 7. 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다
  8. 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 책임을 설명할 수 있나?
13

STEP 13 / 13

전체 원본 source

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

학습용 예시 전체 확인하기 · 정본 답안 아님 · NOT_RUN
학습용 예시 · W25 phase wrapper · 정본 답안 아님 · 로컬 미실행illustrative/powershell/W25-D3-record-red.ps1SHA-256 3999e0395c1e96073030ddfc351b34e79acef601d5b8a66b3044ee2a3eb7f235
D3 RecordRed — exact one-test Red와 XML archive 전체
# 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"
12

SECURITIES solution CashWallet — availableCash 차감 복구

track_learning_stages/securities/w25/solution/src/main/java/com/example/financialcore/securities/CashWallet.java

PDF 전문 정본 · learner solution Java · 정본 · W25-F12
56줄 연결56줄 번역6 chunks
01

STEP 01 / 13

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

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

오늘의 한 문장

reserve에서 availableCash를 amount만큼 차감해 available+reserved 총액 보존을 복구한다.

  1. availableCash -= amount은 어느 source와 실제 결과에서 확인해야 할까?
  2. 첫 실패를 만드는 조건과 fail-closed 지점은 어디일까?
  3. 왜 ‘solution hash만으로 Green은 아니다’를 별도 경계로 남겨야 할까?
이 파일에서 끝까지 다시 쓰는 값availableCash -= amountreservedCash = addExact1_000→700/300nonnegativeLEARNER_AUTHORED after manual entry
왜 필요한가 — SECURITIES solution CashWallet — availableCash 차감 복구히토리 → 니지카 → 료 → 키타
  1. 히토리

    availableCash -= amount가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 reserve에서 availableCash를 amount만큼 차감해 available+reserved 총액 보존을 복구한다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘solution hash만으로 Green은 아니다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 availableCash -= amount와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

02

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 확인을 대신하지 않는다.

03

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이며 실제 실행은 정확히 한 트랙에만 귀속한다
04

STEP 04 / 13

비유 ↔ 코드 전체 연결표

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

단어 몇 개만 뽑은 표가 아닙니다.PDF 전문 정본 · learner solution Java에서 비어 있지 않은 모든 줄을 원본 줄 번호 그대로 연결했습니다.56 / 56 연결
정확한 원본 줄STARRY 비유실제 뜻·입력·결과·한계
1줄F12-L01 package com.example.financialcore.securities; 출고표 1번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 availableCash -= amount
결과·효과
관찰 상태 F12-001가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
solution hash만으로 Green은 아니다
3줄F12-L03 import jakarta.persistence.Column; 출고표 3번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 availableCash -= amount
결과·효과
관찰 상태 F12-003가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
DB lock·동시 예약은 범위 밖이다
4줄F12-L04 import jakarta.persistence.Entity; 출고표 4번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 availableCash -= amount
결과·효과
관찰 상태 F12-004가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
5줄F12-L05 import jakarta.persistence.GeneratedValue; 출고표 5번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 availableCash -= amount
결과·효과
관찰 상태 F12-005가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
6줄F12-L06 import jakarta.persistence.GenerationType; 출고표 6번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 availableCash -= amount
결과·효과
관찰 상태 F12-006가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
7줄F12-L07 import jakarta.persistence.Id; 출고표 7번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 availableCash -= amount
결과·효과
관찰 상태 F12-007가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
solution hash만으로 Green은 아니다
8줄F12-L08 import jakarta.persistence.Table; 출고표 8번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 availableCash -= amount
결과·효과
관찰 상태 F12-008가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
0/10_000은 별도 scenario가 필요하다
9줄F12-L09 import jakarta.persistence.Version; 출고표 9번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 availableCash -= amount
결과·효과
관찰 상태 F12-009가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
DB lock·동시 예약은 범위 밖이다
11줄F12-L11 @Entity 출고표 11번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 availableCash -= amount
결과·효과
관찰 상태 F12-011가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
12줄F12-L12 @Table(name = "securities_cash_wallet") 출고표 12번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
입력
"securities_cash_wallet"
결과·효과
관찰 상태 F12-012가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
13줄F12-L13 public class CashWallet { 출고표 13번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 조건·반복·함수의 실행 block을 연다.
입력
이전 줄의 상태와 availableCash -= amount
결과·효과
관찰 상태 F12-013가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
solution hash만으로 Green은 아니다
14줄F12-L14 @Id 출고표 14번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 availableCash -= amount
결과·효과
관찰 상태 F12-014가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
0/10_000은 별도 scenario가 필요하다
15줄F12-L15 @GeneratedValue(strategy = GenerationType.IDENTITY) 출고표 15번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 availableCash -= amount
결과·효과
관찰 상태 F12-015가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
DB lock·동시 예약은 범위 밖이다
16줄F12-L16 private Long id; 출고표 16번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 availableCash -= amount
결과·효과
관찰 상태 F12-016가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
18줄F12-L18 @Column(name = "investor_key", nullable = false, unique = true, length = 64) 출고표 18번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
입력
"investor_key", 64
결과·효과
관찰 상태 F12-018가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
19줄F12-L19 private String investorKey; 출고표 19번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 availableCash -= amount
결과·효과
관찰 상태 F12-019가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
solution hash만으로 Green은 아니다
21줄F12-L21 @Column(name = "available_cash", nullable = false) 출고표 21번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
입력
"available_cash"
결과·효과
관찰 상태 F12-021가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
DB lock·동시 예약은 범위 밖이다
22줄F12-L22 private long availableCash; 출고표 22번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 availableCash -= amount
결과·효과
관찰 상태 F12-022가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
24줄F12-L24 @Column(name = "reserved_cash", nullable = false) 출고표 24번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
입력
"reserved_cash"
결과·효과
관찰 상태 F12-024가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
25줄F12-L25 private long reservedCash; 출고표 25번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 availableCash -= amount
결과·효과
관찰 상태 F12-025가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
solution hash만으로 Green은 아니다
27줄F12-L27 @Version 출고표 27번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 availableCash -= amount
결과·효과
관찰 상태 F12-027가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
DB lock·동시 예약은 범위 밖이다
28줄F12-L28 private long version; 출고표 28번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 availableCash -= amount
결과·효과
관찰 상태 F12-028가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
30줄F12-L30 protected CashWallet() {} 출고표 30번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 availableCash -= amount
결과·효과
관찰 상태 F12-030가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
32줄F12-L32 private CashWallet(String investorKey, long availableCash) { 출고표 32번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 조건·반복·함수의 실행 block을 연다.
입력
이전 줄의 상태와 availableCash -= amount
결과·효과
관찰 상태 F12-032가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
0/10_000은 별도 scenario가 필요하다
33줄F12-L33 if (investorKey == null || investorKey.isBlank()) throw new IllegalArgumentException("investorKey"); 출고표 33번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
입력
"investorKey"
결과·효과
관찰 상태 F12-033가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
DB lock·동시 예약은 범위 밖이다
34줄F12-L34 if (availableCash < 0) throw new IllegalArgumentException("availableCash"); 출고표 34번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
입력
0, "availableCash"
결과·효과
관찰 상태 F12-034가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
35줄F12-L35 this.investorKey = investorKey; 출고표 35번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 availableCash -= amount
결과·효과
관찰 상태 F12-035가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
36줄F12-L36 this.availableCash = availableCash; 출고표 36번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 availableCash -= amount
결과·효과
관찰 상태 F12-036가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
37줄F12-L37 } 출고표 37번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
입력
이전 줄의 상태와 availableCash -= amount
결과·효과
관찰 상태 F12-037가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
solution hash만으로 Green은 아니다
39줄F12-L39 public static CashWallet open(String investorKey, long availableCash) { 출고표 39번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 조건·반복·함수의 실행 block을 연다.
입력
이전 줄의 상태와 availableCash -= amount
결과·효과
관찰 상태 F12-039가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
DB lock·동시 예약은 범위 밖이다
40줄F12-L40 return new CashWallet(investorKey, availableCash); 출고표 40번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 availableCash -= amount
결과·효과
관찰 상태 F12-040가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
41줄F12-L41 } 출고표 41번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
입력
이전 줄의 상태와 availableCash -= amount
결과·효과
관찰 상태 F12-041가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
43줄F12-L43 public void reserve(long amount) { 출고표 43번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 조건·반복·함수의 실행 block을 연다.
입력
이전 줄의 상태와 availableCash -= amount
결과·효과
관찰 상태 F12-043가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
solution hash만으로 Green은 아니다
44줄F12-L44 if (amount <= 0) throw new IllegalArgumentException("amount"); 출고표 44번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
입력
0, "amount"
결과·효과
관찰 상태 F12-044가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
0/10_000은 별도 scenario가 필요하다
45줄F12-L45 if (availableCash < amount) throw new IllegalStateException("INSUFFICIENT_AVAILABLE_CASH"); 출고표 45번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
입력
"INSUFFICIENT_AVAILABLE_CASH"
결과·효과
관찰 상태 F12-045가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
DB lock·동시 예약은 범위 밖이다
46줄F12-L46 availableCash -= amount; 출고표 46번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 solution에서 예약액만큼 가용 현금을 실제로 차감한다.
입력
이전 줄의 상태와 availableCash -= amount
결과·효과
관찰 상태 F12-046가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
47줄F12-L47 reservedCash = Math.addExact(reservedCash, amount); 출고표 47번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 availableCash -= amount
결과·효과
관찰 상태 F12-047가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
48줄F12-L48 } 출고표 48번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
입력
이전 줄의 상태와 availableCash -= amount
결과·효과
관찰 상태 F12-048가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
50줄F12-L50 public void settle(long reservedAmount, long executedAmount) { 출고표 50번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 조건·반복·함수의 실행 block을 연다.
입력
이전 줄의 상태와 availableCash -= amount
결과·효과
관찰 상태 F12-050가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
0/10_000은 별도 scenario가 필요하다
51줄F12-L51 if (reservedAmount <= 0 || executedAmount <= 0 || executedAmount > reservedAmount) { 출고표 51번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 Markdown 표 또는 PowerShell pipeline에서 값을 열이나 다음 명령으로 연결한다.
입력
0, 0
결과·효과
관찰 상태 F12-051가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
DB lock·동시 예약은 범위 밖이다
52줄F12-L52 throw new IllegalArgumentException("settlement amount"); 출고표 52번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
입력
"settlement amount"
결과·효과
관찰 상태 F12-052가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
53줄F12-L53 } 출고표 53번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
입력
이전 줄의 상태와 availableCash -= amount
결과·효과
관찰 상태 F12-053가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
54줄F12-L54 if (reservedCash < reservedAmount) throw new IllegalStateException("RESERVATION_MISMATCH"); 출고표 54번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
입력
"RESERVATION_MISMATCH"
결과·효과
관찰 상태 F12-054가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
55줄F12-L55 reservedCash -= reservedAmount; 출고표 55번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 availableCash -= amount
결과·효과
관찰 상태 F12-055가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
solution hash만으로 Green은 아니다
56줄F12-L56 availableCash = Math.addExact(availableCash, reservedAmount - executedAmount); 출고표 56번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 availableCash -= amount
결과·효과
관찰 상태 F12-056가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
0/10_000은 별도 scenario가 필요하다
57줄F12-L57 } 출고표 57번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
입력
이전 줄의 상태와 availableCash -= amount
결과·효과
관찰 상태 F12-057가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
DB lock·동시 예약은 범위 밖이다
59줄F12-L59 public void releaseReservation(long amount) { 출고표 59번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 조건·반복·함수의 실행 block을 연다.
입력
이전 줄의 상태와 availableCash -= amount
결과·효과
관찰 상태 F12-059가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
60줄F12-L60 if (amount <= 0 || reservedCash < amount) throw new IllegalArgumentException("amount"); 출고표 60번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
입력
0, "amount"
결과·효과
관찰 상태 F12-060가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
61줄F12-L61 reservedCash -= amount; 출고표 61번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 availableCash -= amount
결과·효과
관찰 상태 F12-061가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
solution hash만으로 Green은 아니다
62줄F12-L62 availableCash = Math.addExact(availableCash, amount); 출고표 62번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 availableCash -= amount
결과·효과
관찰 상태 F12-062가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
0/10_000은 별도 scenario가 필요하다
63줄F12-L63 } 출고표 63번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
입력
이전 줄의 상태와 availableCash -= amount
결과·효과
관찰 상태 F12-063가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
DB lock·동시 예약은 범위 밖이다
65줄F12-L65 public Long getId() { return id; } 출고표 65번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 availableCash -= amount
결과·효과
관찰 상태 F12-065가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
66줄F12-L66 public String getInvestorKey() { return investorKey; } 출고표 66번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 availableCash -= amount
결과·효과
관찰 상태 F12-066가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
67줄F12-L67 public long getAvailableCash() { return availableCash; } 출고표 67번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 예약 뒤 가용 현금이 700인지 관찰한다.
입력
이전 줄의 상태와 availableCash -= amount
결과·효과
관찰 상태 F12-067가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
solution hash만으로 Green은 아니다
68줄F12-L68 public long getReservedCash() { return reservedCash; } 출고표 68번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 예약 뒤 예약 현금이 300인지 관찰한다.
입력
이전 줄의 상태와 availableCash -= amount
결과·효과
관찰 상태 F12-068가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
0/10_000은 별도 scenario가 필요하다
69줄F12-L69 } 출고표 69번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
입력
이전 줄의 상태와 availableCash -= amount
결과·효과
관찰 상태 F12-069가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
DB lock·동시 예약은 범위 밖이다
05

STEP 05 / 13

원본 코드 조각

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

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

F12-C01 · 원문 1–12줄1–12줄
1–12줄 원본
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")
F12-C02 · 원문 13–24줄13–24줄
13–24줄 원본
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)
F12-C03 · 원문 25–36줄25–36줄
25–36줄 원본
    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;
F12-C04 · 원문 37–48줄37–48줄
37–48줄 원본
    }

    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);
    }
F12-C05 · 원문 49–60줄49–60줄
49–60줄 원본

    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");
F12-C06 · 원문 61–69줄61–69줄
61–69줄 원본
        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; }
}
06

STEP 06 / 13

코드 한 줄씩 한국어로 번역

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

전체 번역 56 / 56

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

원본한국어 번역
1package com.example.financialcore.securities;실행 의미: CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
3import jakarta.persistence.Column;실행 의미: CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
4import jakarta.persistence.Entity;실행 의미: CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
5import jakarta.persistence.GeneratedValue;실행 의미: CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
6import jakarta.persistence.GenerationType;실행 의미: CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
7import jakarta.persistence.Id;실행 의미: CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
8import jakarta.persistence.Table;실행 의미: CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
9import jakarta.persistence.Version;실행 의미: CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
11@Entity실행 의미: CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
12@Table(name = "securities_cash_wallet")실행 의미: CashWallet.java의 다음 검증 또는 설명 단계를 구성한다.
13public 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 또는 호출 범위를 닫는다.
07

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를 서로 대체하지 않는다.

실행 순서

  1. 기본 트랙은 SECURITIES(증권)이며, 명시적 CARD 선택은 기본값을 덮어쓴다. 실제 실행 전 최종 선택 한 개를 selected-track.csv·근거·state에 같은 값으로 기록하고 서로 다른 reference/learner root를 확인한다.
  2. Prepare→VerifyStarter→RecordRed→VerifySolution→RecordGreen→Cumulative→Review 순서를 지킨다.
  3. test를 소유한 세 phase에서만 native exit와 exact JUnit XML 수치를 판정한다.
  4. 다음 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 차감 복구히토리 → 니지카 → 료 → 키타
  1. 히토리

    reservedCash = addExact가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 reserve에서 availableCash를 amount만큼 차감해 available+reserved 총액 보존을 복구한다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘0/10_000은 별도 scenario가 필요하다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 reservedCash = addExact와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

08

STEP 08 / 13

실제 값 따라가기

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

순서들어온 값코드가 하는 일나온 값·상태경계
입력availableCash -= amountsource 계약에 대입F12 실행/설명 시작 상태solution hash만으로 Green은 아니다
검증reservedCash = addExactexpected와 actual 또는 형식 대조통과 또는 첫 mismatch0/10_000은 별도 scenario가 필요하다
증거LEARNER_AUTHORED after manual entrymarker·hash·row를 같은 run에 연결범위가 적힌 evidence 후보이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
실제 값 — SECURITIES solution CashWallet — availableCash 차감 복구히토리 → 니지카 → 료 → 키타
  1. 히토리

    1_000→700/300가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 reserve에서 availableCash를 amount만큼 차감해 available+reserved 총액 보존을 복구한다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘DB lock·동시 예약은 범위 밖이다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 1_000→700/300와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

09

STEP 09 / 13

Gradle·JUnit XML·PowerShell·SQL 내부에서 벌어지는 일

세 test phase, XML bytes archive, Review, 별도 Q41, USER_ATTESTED sealed 결과의 owner와 증명 범위를 구분합니다.

source/contract

CashWallet.java bytes와 track·phase·hash 계약을 읽는다.

SECURITIES 기본 선택과 파일 존재·phase 이름만으로 runtime Green을 주장할 수 없다. 실제 selected-track evidence와 실행 결과는 별도다.
execution/evidence

RecordRed·RecordGreen·Cumulative에서만 native exit와 exact JUnit XML을 만든다.

solution hash만으로 Green은 아니다
retention/review

XML bytes를 고유 파일로 보존하고 history hash와 묶은 뒤, Review는 기존 CumulativeGreen만 인용한다. Q41은 별도 PostgreSQL evidence, sealed official status는 user-attested evidence로 남긴다.

이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
첫 실패 경계 — SECURITIES solution CashWallet — availableCash 차감 복구히토리 → 니지카 → 료 → 키타
  1. 히토리

    nonnegative가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 reserve에서 availableCash를 amount만큼 차감해 available+reserved 총액 보존을 복구한다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘reference와 learner root는 서로 달라야 한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 nonnegative와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

10

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이 생기지 않는다.

11

STEP 11 / 13

이 코드가 보장하지 않는 것

선택 미결정·10_000 finalState·XML 보존·Review/Q41/sealed official truth처럼 이 코드가 책임지지 않는 일을 분리합니다.

증명 범위

solution hash만으로 Green은 아니다

이 책임을 맡는 곳: runtime Gate
증명 범위

0/10_000은 별도 scenario가 필요하다

이 책임을 맡는 곳: external/human review
증명 범위

DB lock·동시 예약은 범위 밖이다

이 책임을 맡는 곳: release manifest
증명 범위

reference와 learner root는 서로 달라야 한다

이 책임을 맡는 곳: 운영 환경
증명하지 않는 범위 — SECURITIES solution CashWallet — availableCash 차감 복구히토리 → 니지카 → 료 → 키타
  1. 히토리

    LEARNER_AUTHORED after manual entry가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 reserve에서 availableCash를 amount만큼 차감해 available+reserved 총액 보존을 복구한다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 LEARNER_AUTHORED after manual entry와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

12

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. 1. CashWallet.java의 다음 검증 또는 설명 단계를 구성한다
  2. 3. CashWallet.java의 다음 검증 또는 설명 단계를 구성한다
  3. 4. CashWallet.java의 다음 검증 또는 설명 단계를 구성한다
  4. 5. CashWallet.java의 다음 검증 또는 설명 단계를 구성한다
  5. 6. CashWallet.java의 다음 검증 또는 설명 단계를 구성한다
  6. 7. CashWallet.java의 다음 검증 또는 설명 단계를 구성한다
  7. 8. CashWallet.java의 다음 검증 또는 설명 단계를 구성한다
  8. 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 책임을 설명할 수 있나?
13

STEP 13 / 13

전체 원본 source

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

원문 정본 전체 source 확인하기
PDF 전문 정본 · learner solution Javatrack_learning_stages/securities/w25/solution/src/main/java/com/example/financialcore/securities/CashWallet.javaSHA-256 cdf78c1f20d8cdbb6304d89c0d4298e65de7d4eb64b39812c37fda28f26fb411
SECURITIES solution CashWallet — availableCash 차감 복구 전체
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; }
}
13

CARD solution CardAccount — usedAmount 증가 복구

track_learning_stages/card/w25/solution/src/main/java/com/example/financialcore/card/CardAccount.java

PDF 전문 정본 · learner solution Java · 정본 · W25-F13
46줄 연결46줄 번역5 chunks
01

STEP 01 / 13

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

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

오늘의 한 문장

hold에서 usedAmount를 amount만큼 더해 availableLimit+usedAmount 합계 보존을 복구한다.

  1. usedAmount = Math.addExact은 어느 source와 실제 결과에서 확인해야 할까?
  2. 첫 실패를 만드는 조건과 fail-closed 지점은 어디일까?
  3. 왜 ‘solution hash만으로 Green은 아니다’를 별도 경계로 남겨야 할까?
이 파일에서 끝까지 다시 쓰는 값usedAmount = Math.addExactavailable=creditLimit-used1_000→300/700nonnegativeLEARNER_AUTHORED after manual entry
왜 필요한가 — CARD solution CardAccount — usedAmount 증가 복구히토리 → 니지카 → 료 → 키타
  1. 히토리

    usedAmount = Math.addExact가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 hold에서 usedAmount를 amount만큼 더해 availableLimit+usedAmount 합계 보존을 복구한다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘solution hash만으로 Green은 아니다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 usedAmount = Math.addExact와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

02

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 확인을 대신하지 않는다.

03

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이며 실제 실행은 정확히 한 트랙에만 귀속한다
04

STEP 04 / 13

비유 ↔ 코드 전체 연결표

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

단어 몇 개만 뽑은 표가 아닙니다.PDF 전문 정본 · learner solution Java에서 비어 있지 않은 모든 줄을 원본 줄 번호 그대로 연결했습니다.46 / 46 연결
정확한 원본 줄STARRY 비유실제 뜻·입력·결과·한계
1줄F13-L01 package com.example.financialcore.card; 출고표 1번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 usedAmount = Math.addExact
결과·효과
관찰 상태 F13-001가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
solution hash만으로 Green은 아니다
3줄F13-L03 import jakarta.persistence.Column; 출고표 3번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 usedAmount = Math.addExact
결과·효과
관찰 상태 F13-003가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
DB lock·capture/refund는 범위 밖이다
4줄F13-L04 import jakarta.persistence.Entity; 출고표 4번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 usedAmount = Math.addExact
결과·효과
관찰 상태 F13-004가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
5줄F13-L05 import jakarta.persistence.GeneratedValue; 출고표 5번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 usedAmount = Math.addExact
결과·효과
관찰 상태 F13-005가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
6줄F13-L06 import jakarta.persistence.GenerationType; 출고표 6번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 usedAmount = Math.addExact
결과·효과
관찰 상태 F13-006가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
7줄F13-L07 import jakarta.persistence.Id; 출고표 7번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 usedAmount = Math.addExact
결과·효과
관찰 상태 F13-007가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
solution hash만으로 Green은 아니다
8줄F13-L08 import jakarta.persistence.Table; 출고표 8번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 usedAmount = Math.addExact
결과·효과
관찰 상태 F13-008가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
0/10_000은 별도 scenario가 필요하다
9줄F13-L09 import jakarta.persistence.Version; 출고표 9번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 usedAmount = Math.addExact
결과·효과
관찰 상태 F13-009가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
DB lock·capture/refund는 범위 밖이다
11줄F13-L11 @Entity 출고표 11번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 usedAmount = Math.addExact
결과·효과
관찰 상태 F13-011가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
12줄F13-L12 @Table(name = "card_account_template") 출고표 12번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
입력
"card_account_template"
결과·효과
관찰 상태 F13-012가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
13줄F13-L13 public class CardAccount { 출고표 13번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 조건·반복·함수의 실행 block을 연다.
입력
이전 줄의 상태와 usedAmount = Math.addExact
결과·효과
관찰 상태 F13-013가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
solution hash만으로 Green은 아니다
14줄F13-L14 @Id 출고표 14번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 usedAmount = Math.addExact
결과·효과
관찰 상태 F13-014가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
0/10_000은 별도 scenario가 필요하다
15줄F13-L15 @GeneratedValue(strategy = GenerationType.IDENTITY) 출고표 15번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 usedAmount = Math.addExact
결과·효과
관찰 상태 F13-015가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
DB lock·capture/refund는 범위 밖이다
16줄F13-L16 private Long id; 출고표 16번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 usedAmount = Math.addExact
결과·효과
관찰 상태 F13-016가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
18줄F13-L18 @Column(name = "account_key", nullable = false, unique = true, length = 64) 출고표 18번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
입력
"account_key", 64
결과·효과
관찰 상태 F13-018가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
19줄F13-L19 private String accountKey; 출고표 19번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 usedAmount = Math.addExact
결과·효과
관찰 상태 F13-019가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
solution hash만으로 Green은 아니다
21줄F13-L21 @Column(name = "credit_limit", nullable = false) 출고표 21번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
입력
"credit_limit"
결과·효과
관찰 상태 F13-021가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
DB lock·capture/refund는 범위 밖이다
22줄F13-L22 private long creditLimit; 출고표 22번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 usedAmount = Math.addExact
결과·효과
관찰 상태 F13-022가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
24줄F13-L24 @Column(name = "used_amount", nullable = false) 출고표 24번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
입력
"used_amount"
결과·효과
관찰 상태 F13-024가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
25줄F13-L25 private long usedAmount; 출고표 25번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 usedAmount = Math.addExact
결과·효과
관찰 상태 F13-025가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
solution hash만으로 Green은 아니다
27줄F13-L27 @Version 출고표 27번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 usedAmount = Math.addExact
결과·효과
관찰 상태 F13-027가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
DB lock·capture/refund는 범위 밖이다
28줄F13-L28 private long version; 출고표 28번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 usedAmount = Math.addExact
결과·효과
관찰 상태 F13-028가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
30줄F13-L30 protected CardAccount() {} 출고표 30번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 usedAmount = Math.addExact
결과·효과
관찰 상태 F13-030가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
32줄F13-L32 private CardAccount(String accountKey, long creditLimit) { 출고표 32번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 조건·반복·함수의 실행 block을 연다.
입력
이전 줄의 상태와 usedAmount = Math.addExact
결과·효과
관찰 상태 F13-032가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
0/10_000은 별도 scenario가 필요하다
33줄F13-L33 if (accountKey == null || accountKey.isBlank()) throw new IllegalArgumentException("accountKey"); 출고표 33번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
입력
"accountKey"
결과·효과
관찰 상태 F13-033가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
DB lock·capture/refund는 범위 밖이다
34줄F13-L34 if (creditLimit <= 0) throw new IllegalArgumentException("creditLimit"); 출고표 34번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
입력
0, "creditLimit"
결과·효과
관찰 상태 F13-034가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
35줄F13-L35 this.accountKey = accountKey; 출고표 35번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 usedAmount = Math.addExact
결과·효과
관찰 상태 F13-035가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
36줄F13-L36 this.creditLimit = creditLimit; 출고표 36번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 usedAmount = Math.addExact
결과·효과
관찰 상태 F13-036가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
37줄F13-L37 } 출고표 37번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
입력
이전 줄의 상태와 usedAmount = Math.addExact
결과·효과
관찰 상태 F13-037가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
solution hash만으로 Green은 아니다
39줄F13-L39 public static CardAccount open(String accountKey, long creditLimit) { 출고표 39번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 조건·반복·함수의 실행 block을 연다.
입력
이전 줄의 상태와 usedAmount = Math.addExact
결과·효과
관찰 상태 F13-039가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
DB lock·capture/refund는 범위 밖이다
40줄F13-L40 return new CardAccount(accountKey, creditLimit); 출고표 40번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 usedAmount = Math.addExact
결과·효과
관찰 상태 F13-040가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
41줄F13-L41 } 출고표 41번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
입력
이전 줄의 상태와 usedAmount = Math.addExact
결과·효과
관찰 상태 F13-041가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
43줄F13-L43 public void hold(long amount) { 출고표 43번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 조건·반복·함수의 실행 block을 연다.
입력
이전 줄의 상태와 usedAmount = Math.addExact
결과·효과
관찰 상태 F13-043가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
solution hash만으로 Green은 아니다
44줄F13-L44 if (amount <= 0) throw new IllegalArgumentException("amount"); 출고표 44번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
입력
0, "amount"
결과·효과
관찰 상태 F13-044가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
0/10_000은 별도 scenario가 필요하다
45줄F13-L45 if (availableAmount() < amount) throw new IllegalStateException("INSUFFICIENT_AVAILABLE_LIMIT"); 출고표 45번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 hold 뒤 가용 한도가 700인지 관찰한다.
입력
"INSUFFICIENT_AVAILABLE_LIMIT"
결과·효과
관찰 상태 F13-045가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
DB lock·capture/refund는 범위 밖이다
46줄F13-L46 usedAmount = Math.addExact(usedAmount, amount); 출고표 46번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 solution에서 hold 금액을 사용액에 overflow-safe하게 더한다.
입력
이전 줄의 상태와 usedAmount = Math.addExact
결과·효과
관찰 상태 F13-046가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
47줄F13-L47 } 출고표 47번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
입력
이전 줄의 상태와 usedAmount = Math.addExact
결과·효과
관찰 상태 F13-047가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
49줄F13-L49 public void release(long amount) { 출고표 49번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 조건·반복·함수의 실행 block을 연다.
입력
이전 줄의 상태와 usedAmount = Math.addExact
결과·효과
관찰 상태 F13-049가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
solution hash만으로 Green은 아니다
50줄F13-L50 if (amount <= 0 || usedAmount < amount) throw new IllegalArgumentException("amount"); 출고표 50번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
입력
0, "amount"
결과·효과
관찰 상태 F13-050가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
0/10_000은 별도 scenario가 필요하다
51줄F13-L51 usedAmount -= amount; 출고표 51번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 usedAmount = Math.addExact
결과·효과
관찰 상태 F13-051가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
DB lock·capture/refund는 범위 밖이다
52줄F13-L52 } 출고표 52번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
입력
이전 줄의 상태와 usedAmount = Math.addExact
결과·효과
관찰 상태 F13-052가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
54줄F13-L54 public long availableAmount() { return creditLimit - usedAmount; } 출고표 54번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 hold 뒤 가용 한도가 700인지 관찰한다.
입력
이전 줄의 상태와 usedAmount = Math.addExact
결과·효과
관찰 상태 F13-054가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
55줄F13-L55 public Long getId() { return id; } 출고표 55번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 usedAmount = Math.addExact
결과·효과
관찰 상태 F13-055가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
solution hash만으로 Green은 아니다
56줄F13-L56 public String getAccountKey() { return accountKey; } 출고표 56번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 usedAmount = Math.addExact
결과·효과
관찰 상태 F13-056가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
0/10_000은 별도 scenario가 필요하다
57줄F13-L57 public long getUsedAmount() { return usedAmount; } 출고표 57번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 hold 뒤 사용액이 300인지 관찰한다.
입력
이전 줄의 상태와 usedAmount = Math.addExact
결과·효과
관찰 상태 F13-057가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
DB lock·capture/refund는 범위 밖이다
58줄F13-L58 } 출고표 58번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
입력
이전 줄의 상태와 usedAmount = Math.addExact
결과·효과
관찰 상태 F13-058가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
05

STEP 05 / 13

원본 코드 조각

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

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

F13-C01 · 원문 1–12줄1–12줄
1–12줄 원본
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")
F13-C02 · 원문 13–24줄13–24줄
13–24줄 원본
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)
F13-C03 · 원문 25–36줄25–36줄
25–36줄 원본
    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;
F13-C04 · 원문 37–48줄37–48줄
37–48줄 원본
    }

    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);
    }
F13-C05 · 원문 49–58줄49–58줄
49–58줄 원본
    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; }
}
06

STEP 06 / 13

코드 한 줄씩 한국어로 번역

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

전체 번역 46 / 46

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

원본한국어 번역
1package com.example.financialcore.card;실행 의미: CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
3import jakarta.persistence.Column;실행 의미: CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
4import jakarta.persistence.Entity;실행 의미: CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
5import jakarta.persistence.GeneratedValue;실행 의미: CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
6import jakarta.persistence.GenerationType;실행 의미: CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
7import jakarta.persistence.Id;실행 의미: CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
8import jakarta.persistence.Table;실행 의미: CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
9import jakarta.persistence.Version;실행 의미: CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
11@Entity실행 의미: CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
12@Table(name = "card_account_template")실행 의미: CardAccount.java의 다음 검증 또는 설명 단계를 구성한다.
13public 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 또는 호출 범위를 닫는다.
07

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를 서로 대체하지 않는다.

실행 순서

  1. 기본 트랙은 SECURITIES(증권)이며, 명시적 CARD 선택은 기본값을 덮어쓴다. 실제 실행 전 최종 선택 한 개를 selected-track.csv·근거·state에 같은 값으로 기록하고 서로 다른 reference/learner root를 확인한다.
  2. Prepare→VerifyStarter→RecordRed→VerifySolution→RecordGreen→Cumulative→Review 순서를 지킨다.
  3. test를 소유한 세 phase에서만 native exit와 exact JUnit XML 수치를 판정한다.
  4. 다음 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 증가 복구히토리 → 니지카 → 료 → 키타
  1. 히토리

    available=creditLimit-used가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 hold에서 usedAmount를 amount만큼 더해 availableLimit+usedAmount 합계 보존을 복구한다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘0/10_000은 별도 scenario가 필요하다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 available=creditLimit-used와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

08

STEP 08 / 13

실제 값 따라가기

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

순서들어온 값코드가 하는 일나온 값·상태경계
입력usedAmount = Math.addExactsource 계약에 대입F13 실행/설명 시작 상태solution hash만으로 Green은 아니다
검증available=creditLimit-usedexpected와 actual 또는 형식 대조통과 또는 첫 mismatch0/10_000은 별도 scenario가 필요하다
증거LEARNER_AUTHORED after manual entrymarker·hash·row를 같은 run에 연결범위가 적힌 evidence 후보이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
실제 값 — CARD solution CardAccount — usedAmount 증가 복구히토리 → 니지카 → 료 → 키타
  1. 히토리

    1_000→300/700가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 hold에서 usedAmount를 amount만큼 더해 availableLimit+usedAmount 합계 보존을 복구한다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘DB lock·capture/refund는 범위 밖이다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 1_000→300/700와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

09

STEP 09 / 13

Gradle·JUnit XML·PowerShell·SQL 내부에서 벌어지는 일

세 test phase, XML bytes archive, Review, 별도 Q41, USER_ATTESTED sealed 결과의 owner와 증명 범위를 구분합니다.

source/contract

CardAccount.java bytes와 track·phase·hash 계약을 읽는다.

SECURITIES 기본 선택과 파일 존재·phase 이름만으로 runtime Green을 주장할 수 없다. 실제 selected-track evidence와 실행 결과는 별도다.
execution/evidence

RecordRed·RecordGreen·Cumulative에서만 native exit와 exact JUnit XML을 만든다.

solution hash만으로 Green은 아니다
retention/review

XML bytes를 고유 파일로 보존하고 history hash와 묶은 뒤, Review는 기존 CumulativeGreen만 인용한다. Q41은 별도 PostgreSQL evidence, sealed official status는 user-attested evidence로 남긴다.

이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
첫 실패 경계 — CARD solution CardAccount — usedAmount 증가 복구히토리 → 니지카 → 료 → 키타
  1. 히토리

    nonnegative가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 hold에서 usedAmount를 amount만큼 더해 availableLimit+usedAmount 합계 보존을 복구한다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘reference와 learner root는 서로 달라야 한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 nonnegative와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

10

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이 생기지 않는다.

11

STEP 11 / 13

이 코드가 보장하지 않는 것

선택 미결정·10_000 finalState·XML 보존·Review/Q41/sealed official truth처럼 이 코드가 책임지지 않는 일을 분리합니다.

증명 범위

solution hash만으로 Green은 아니다

이 책임을 맡는 곳: runtime Gate
증명 범위

0/10_000은 별도 scenario가 필요하다

이 책임을 맡는 곳: external/human review
증명 범위

DB lock·capture/refund는 범위 밖이다

이 책임을 맡는 곳: release manifest
증명 범위

reference와 learner root는 서로 달라야 한다

이 책임을 맡는 곳: 운영 환경
증명하지 않는 범위 — CARD solution CardAccount — usedAmount 증가 복구히토리 → 니지카 → 료 → 키타
  1. 히토리

    LEARNER_AUTHORED after manual entry가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 hold에서 usedAmount를 amount만큼 더해 availableLimit+usedAmount 합계 보존을 복구한다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 LEARNER_AUTHORED after manual entry와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

12

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. 1. CardAccount.java의 다음 검증 또는 설명 단계를 구성한다
  2. 3. CardAccount.java의 다음 검증 또는 설명 단계를 구성한다
  3. 4. CardAccount.java의 다음 검증 또는 설명 단계를 구성한다
  4. 5. CardAccount.java의 다음 검증 또는 설명 단계를 구성한다
  5. 6. CardAccount.java의 다음 검증 또는 설명 단계를 구성한다
  6. 7. CardAccount.java의 다음 검증 또는 설명 단계를 구성한다
  7. 8. CardAccount.java의 다음 검증 또는 설명 단계를 구성한다
  8. 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 책임을 설명할 수 있나?
13

STEP 13 / 13

전체 원본 source

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

원문 정본 전체 source 확인하기
PDF 전문 정본 · learner solution Javatrack_learning_stages/card/w25/solution/src/main/java/com/example/financialcore/card/CardAccount.javaSHA-256 3a142277feffdb89156bbce21dde495d299564a7c1c4a036f7d4505f96fea0e3
CARD solution CardAccount — usedAmount 증가 복구 전체
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; }
}
14

D4 VerifySolution — solution hash와 별도 10_000 oracle 경계

illustrative/powershell/W25-D4-verify-solution.ps1

학습용 예시 · W25 phase wrapper · 정본 답안 아님 · 로컬 미실행 · 학습용 예시 · 정본 답안 아님 · NOT_RUN · W25-F14
25줄 연결25줄 번역3 chunks
01

STEP 01 / 13

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

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

오늘의 한 문장

LearnerRed 이후 선택 트랙 solution canonical/raw hash를 확인하되 새 Gradle/XML Green이 없음을 확인한다.

  1. LearnerRed은 어느 source와 실제 결과에서 확인해야 할까?
  2. 첫 실패를 만드는 조건과 fail-closed 지점은 어디일까?
  3. 왜 ‘hash 일치는 실행 성공이 아니다’를 별도 경계로 남겨야 할까?
이 파일에서 끝까지 다시 쓰는 값LearnerRedSolutionVerifiedsolutionSha2560/10_000 needs separate testruntime_claim=false
왜 필요한가 — D4 VerifySolution — solution hash와 별도 10_000 oracle 경계히토리 → 니지카 → 료 → 키타
  1. 히토리

    LearnerRed가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 LearnerRed 이후 선택 트랙 solution canonical/raw hash를 확인하되 새 Gradle/XML Green이 없음을 확인한다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘hash 일치는 실행 성공이 아니다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 LearnerRed와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

02

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 확인을 대신하지 않는다.

03

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을 실행하지 않았다
04

STEP 04 / 13

비유 ↔ 코드 전체 연결표

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

단어 몇 개만 뽑은 표가 아닙니다.학습용 예시 · W25 phase wrapper · 정본 답안 아님 · 로컬 미실행에서 비어 있지 않은 모든 줄을 원본 줄 번호 그대로 연결했습니다.25 / 25 연결
정확한 원본 줄STARRY 비유실제 뜻·입력·결과·한계
1줄F14-L01 # W25 PDF p23-p31의 VerifySolution 흐름을 정리한 학습용 예시다. 출고표 1번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 solution canonical/raw hash만 검증하고 새 Green을 만들지 않는 phase다.
입력
이전 줄의 상태와 LearnerRed
결과·효과
관찰 상태 F14-001가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
hash 일치는 실행 성공이 아니다
2줄F14-L02 # solution canonical/raw hash와 learner ownership을 검증하지만 새 test Green은 만들지 않는다. 출고표 2번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다.
입력
이전 줄의 상태와 LearnerRed
결과·효과
관찰 상태 F14-002가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
manifest finalState는 runtime이 parse/assert하지 않는다
3줄F14-L03 $ErrorActionPreference = 'Stop' 출고표 3번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 PowerShell 오류를 계속 진행하지 않고 중단시키는 기본 정책을 둔다.
입력
$ErrorActionPreference, 'Stop'
결과·효과
관찰 상태 F14-003가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
4줄F14-L04 $ReferenceRoot = (Resolve-Path -LiteralPath $env:FINANCIAL_IT_REFERENCE_ROOT).Path 출고표 4번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 입력 경로를 실제 절대 경로로 확인한다.
입력
$ReferenceRoot, $env
결과·효과
관찰 상태 F14-004가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
5줄F14-L05 $LearnerRoot = (Resolve-Path -LiteralPath $env:FINANCIAL_IT_LEARNER_ROOT).Path 출고표 5번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 입력 경로를 실제 절대 경로로 확인한다.
입력
$LearnerRoot, $env
결과·효과
관찰 상태 F14-005가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
6줄F14-L06 if ([string]::Equals($ReferenceRoot, $LearnerRoot, [StringComparison]::OrdinalIgnoreCase)) { 출고표 6번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 조건·반복·함수의 실행 block을 연다.
입력
$ReferenceRoot, $LearnerRoot
결과·효과
관찰 상태 F14-006가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
hash 일치는 실행 성공이 아니다
7줄F14-L07 throw 'reference and learner roots must be different' 출고표 7번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
입력
이전 줄의 상태와 LearnerRed
결과·효과
관찰 상태 F14-007가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
manifest finalState는 runtime이 parse/assert하지 않는다
8줄F14-L08 } 출고표 8번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
입력
이전 줄의 상태와 LearnerRed
결과·효과
관찰 상태 F14-008가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
9줄F14-L09 $Before = Get-Content -Raw -LiteralPath (Join-Path $LearnerRoot '.track-learning-stage.json') | ConvertFrom-Json 출고표 9번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 JSON text를 필드로 접근 가능한 PowerShell object로 바꾼다.
입력
$Before, $LearnerRoot, '.track-learning-stage.json'
결과·효과
관찰 상태 F14-009가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
10줄F14-L10 if ($Before.phase -cne 'LearnerRed') { throw 'VerifySolution requires LearnerRed' } 출고표 10번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 solution canonical/raw hash만 검증하고 새 Green을 만들지 않는 phase다.
입력
$Before, 'LearnerRed', 'VerifySolution requires LearnerRed'
결과·효과
관찰 상태 F14-010가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
12줄F14-L12 $Runner = Join-Path $ReferenceRoot 'scripts\apply-track-learning-stage.ps1' 출고표 12번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
입력
$Runner, $ReferenceRoot, 'scripts\apply-track-learning-stage.ps1'
결과·효과
관찰 상태 F14-012가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
manifest finalState는 runtime이 parse/assert하지 않는다
13줄F14-L13 & powershell.exe -NoProfile -ExecutionPolicy Bypass -File $Runner ` 출고표 13번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 W25-D4-verify-solution.ps1의 다음 검증 또는 설명 단계를 구성한다.
입력
$Runner
결과·효과
관찰 상태 F14-013가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
14줄F14-L14 -ReferenceRoot $ReferenceRoot -LearnerRoot $LearnerRoot -Week 25 -Phase VerifySolution -TimeoutSeconds 1200 출고표 14번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 solution canonical/raw hash만 검증하고 새 Green을 만들지 않는 phase다.
입력
$ReferenceRoot, $LearnerRoot, 25
결과·효과
관찰 상태 F14-014가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
15줄F14-L15 if ($LASTEXITCODE -ne 0) { throw "W25 VerifySolution native exit=$LASTEXITCODE" } 출고표 15번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 solution canonical/raw hash만 검증하고 새 Green을 만들지 않는 phase다.
입력
$LASTEXITCODE, 0, $LASTEXITCODE
결과·효과
관찰 상태 F14-015가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
17줄F14-L17 $StatePath = Join-Path $LearnerRoot '.track-learning-stage.json' 출고표 17번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
입력
$StatePath, $LearnerRoot, '.track-learning-stage.json'
결과·효과
관찰 상태 F14-017가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
manifest finalState는 runtime이 parse/assert하지 않는다
18줄F14-L18 $State = Get-Content -Raw -LiteralPath $StatePath | ConvertFrom-Json 출고표 18번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 JSON text를 필드로 접근 가능한 PowerShell object로 바꾼다.
입력
$State, $StatePath
결과·효과
관찰 상태 F14-018가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
19줄F14-L19 $Entry = @($State.history)[-1] 출고표 19번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
입력
$Entry, $State, 1
결과·효과
관찰 상태 F14-019가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
20줄F14-L20 if ($State.phase -cne 'SolutionVerified' -or $Entry.phase -cne 'VerifySolution') { 출고표 20번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 solution canonical/raw hash만 검증하고 새 Green을 만들지 않는 phase다.
입력
$State, 'SolutionVerified', $Entry
결과·효과
관찰 상태 F14-020가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
21줄F14-L21 throw 'W25 VerifySolution state mismatch' 출고표 21번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 solution canonical/raw hash만 검증하고 새 Green을 만들지 않는 phase다.
입력
'W25 VerifySolution state mismatch'
결과·효과
관찰 상태 F14-021가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
hash 일치는 실행 성공이 아니다
22줄F14-L22 } 출고표 22번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
입력
이전 줄의 상태와 LearnerRed
결과·효과
관찰 상태 F14-022가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
manifest finalState는 runtime이 parse/assert하지 않는다
23줄F14-L23 if ($null -eq $Entry.authoredTarget -or $null -ne $Entry.execution) { 출고표 23번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 학습자가 직접 소유하는 main Java 경로와 starter/solution hash를 묶는다.
입력
$null, $Entry, $null
결과·효과
관찰 상태 F14-023가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
24줄F14-L24 throw 'VerifySolution must record authoredTarget without new execution evidence' 출고표 24번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 학습자가 직접 소유하는 main Java 경로와 starter/solution hash를 묶는다.
입력
이전 줄의 상태와 LearnerRed
결과·효과
관찰 상태 F14-024가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
25줄F14-L25 } 출고표 25번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
입력
이전 줄의 상태와 LearnerRed
결과·효과
관찰 상태 F14-025가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
26줄F14-L26 $Hash = (Get-FileHash -LiteralPath $StatePath -Algorithm SHA256).Hash.ToLowerInvariant() 출고표 26번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 현재 bytes를 64자리 digest로 evidence에 결박한다.
입력
$Hash, $StatePath
결과·효과
관찰 상태 F14-026가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
hash 일치는 실행 성공이 아니다
27줄F14-L27 "W25_SOLUTION_HASH_VERIFIED phase=SolutionVerified runtime_claim=false state_sha256=$Hash" 출고표 27번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 현재 bytes를 64자리 digest로 evidence에 결박한다.
입력
$Hash
결과·효과
관찰 상태 F14-027가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
manifest finalState는 runtime이 parse/assert하지 않는다
05

STEP 05 / 13

원본 코드 조각

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

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

F14-C01 · 원문 1–12줄1–12줄
1–12줄 원본
# 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'
F14-C02 · 원문 13–24줄13–24줄
13–24줄 원본
& 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'
F14-C03 · 원문 25–27줄25–27줄
25–27줄 원본
}
$Hash = (Get-FileHash -LiteralPath $StatePath -Algorithm SHA256).Hash.ToLowerInvariant()
"W25_SOLUTION_HASH_VERIFIED phase=SolutionVerified runtime_claim=false state_sha256=$Hash"
06

STEP 06 / 13

코드 한 줄씩 한국어로 번역

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

전체 번역 25 / 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실행 의미: 입력 경로를 실제 절대 경로로 확인한다.
6if ([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로 바꾼다.
10if ($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다.
15if ($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 변수에 저장한다.
20if ($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 또는 호출 범위를 닫는다.
23if ($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에 결박한다.
07

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를 서로 대체하지 않는다.

실행 순서

  1. 기본 트랙은 SECURITIES(증권)이며, 명시적 CARD 선택은 기본값을 덮어쓴다. 실제 실행 전 최종 선택 한 개를 selected-track.csv·근거·state에 같은 값으로 기록하고 서로 다른 reference/learner root를 확인한다.
  2. Prepare→VerifyStarter→RecordRed→VerifySolution→RecordGreen→Cumulative→Review 순서를 지킨다.
  3. test를 소유한 세 phase에서만 native exit와 exact JUnit XML 수치를 판정한다.
  4. 다음 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 경계히토리 → 니지카 → 료 → 키타
  1. 히토리

    SolutionVerified가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 LearnerRed 이후 선택 트랙 solution canonical/raw hash를 확인하되 새 Gradle/XML Green이 없음을 확인한다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘manifest finalState는 runtime이 parse/assert하지 않는다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 SolutionVerified와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

08

STEP 08 / 13

실제 값 따라가기

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

순서들어온 값코드가 하는 일나온 값·상태경계
입력LearnerRedsource 계약에 대입F14 실행/설명 시작 상태hash 일치는 실행 성공이 아니다
검증SolutionVerifiedexpected와 actual 또는 형식 대조통과 또는 첫 mismatchmanifest finalState는 runtime이 parse/assert하지 않는다
증거runtime_claim=falsemarker·hash·row를 같은 run에 연결범위가 적힌 evidence 후보이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
실제 값 — D4 VerifySolution — solution hash와 별도 10_000 oracle 경계히토리 → 니지카 → 료 → 키타
  1. 히토리

    solutionSha256가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 LearnerRed 이후 선택 트랙 solution canonical/raw hash를 확인하되 새 Gradle/XML Green이 없음을 확인한다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘reference와 learner root는 서로 달라야 한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 solutionSha256와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

09

STEP 09 / 13

Gradle·JUnit XML·PowerShell·SQL 내부에서 벌어지는 일

세 test phase, XML bytes archive, Review, 별도 Q41, USER_ATTESTED sealed 결과의 owner와 증명 범위를 구분합니다.

source/contract

W25-D4-verify-solution.ps1 bytes와 track·phase·hash 계약을 읽는다.

SECURITIES 기본 선택과 파일 존재·phase 이름만으로 runtime Green을 주장할 수 없다. 실제 selected-track evidence와 실행 결과는 별도다.
execution/evidence

RecordRed·RecordGreen·Cumulative에서만 native exit와 exact JUnit XML을 만든다.

hash 일치는 실행 성공이 아니다
retention/review

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 경계히토리 → 니지카 → 료 → 키타
  1. 히토리

    0/10_000 needs separate test가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 LearnerRed 이후 선택 트랙 solution canonical/raw hash를 확인하되 새 Gradle/XML Green이 없음을 확인한다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 0/10_000 needs separate test와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

10

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이 생기지 않는다.

11

STEP 11 / 13

이 코드가 보장하지 않는 것

선택 미결정·10_000 finalState·XML 보존·Review/Q41/sealed official truth처럼 이 코드가 책임지지 않는 일을 분리합니다.

증명 범위

hash 일치는 실행 성공이 아니다

이 책임을 맡는 곳: runtime Gate
증명 범위

manifest finalState는 runtime이 parse/assert하지 않는다

이 책임을 맡는 곳: external/human review
증명 범위

reference와 learner root는 서로 달라야 한다

이 책임을 맡는 곳: release manifest
증명 범위

기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다

이 책임을 맡는 곳: 운영 환경
증명하지 않는 범위 — D4 VerifySolution — solution hash와 별도 10_000 oracle 경계히토리 → 니지카 → 료 → 키타
  1. 히토리

    runtime_claim=false가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 LearnerRed 이후 선택 트랙 solution canonical/raw hash를 확인하되 새 Gradle/XML Green이 없음을 확인한다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 runtime_claim=false와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

12

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. 1. solution canonical/raw hash만 검증하고 새 Green을 만들지 않는 phase다
  2. 2. 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다
  3. 3. PowerShell 오류를 계속 진행하지 않고 중단시키는 기본 정책을 둔다
  4. 4. 입력 경로를 실제 절대 경로로 확인한다
  5. 5. 입력 경로를 실제 절대 경로로 확인한다
  6. 6. 조건·반복·함수의 실행 block을 연다
  7. 7. 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다
  8. 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 책임을 설명할 수 있나?
13

STEP 13 / 13

전체 원본 source

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

학습용 예시 전체 확인하기 · 정본 답안 아님 · NOT_RUN
학습용 예시 · W25 phase wrapper · 정본 답안 아님 · 로컬 미실행illustrative/powershell/W25-D4-verify-solution.ps1SHA-256 395070bab4a6f4ce23fee74d97bb27da73885745040f238b3edb20bcf56538e7
D4 VerifySolution — solution hash와 별도 10_000 oracle 경계 전체
# 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"
15

D5 RecordGreen — current selector exact Green과 XML archive

illustrative/powershell/W25-D5-record-green.ps1

학습용 예시 · W25 phase wrapper · 정본 답안 아님 · 로컬 미실행 · 학습용 예시 · 정본 답안 아님 · NOT_RUN · W25-F15
31줄 연결31줄 번역3 chunks
01

STEP 01 / 13

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

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

오늘의 한 문장

native 0·tests=1·failure/error/skip=0을 확인하고 Green XML bytes를 history hash와 결박해 보존한다.

  1. LearnerGreen은 어느 source와 실제 결과에서 확인해야 할까?
  2. 첫 실패를 만드는 조건과 fail-closed 지점은 어디일까?
  3. 왜 ‘700/300 Green은 10_000 finalState나 Q41을 증명하지 않는다’를 별도 경계로 남겨야 할까?
이 파일에서 끝까지 다시 쓰는 값LearnerGreennativeExit=0tests=1status totals=0green-exact.xml
왜 필요한가 — D5 RecordGreen — current selector exact Green과 XML archive히토리 → 니지카 → 료 → 키타
  1. 히토리

    LearnerGreen가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 native 0·tests=1·failure/error/skip=0을 확인하고 Green XML bytes를 history hash와 결박해 보존한다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘700/300 Green은 10_000 finalState나 Q41을 증명하지 않는다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 LearnerGreen와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

02

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 확인을 대신하지 않는다.

03

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을 실행하지 않았다
04

STEP 04 / 13

비유 ↔ 코드 전체 연결표

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

단어 몇 개만 뽑은 표가 아닙니다.학습용 예시 · W25 phase wrapper · 정본 답안 아님 · 로컬 미실행에서 비어 있지 않은 모든 줄을 원본 줄 번호 그대로 연결했습니다.31 / 31 연결
정확한 원본 줄STARRY 비유실제 뜻·입력·결과·한계
1줄F15-L01 # W25 PDF p32-p37의 current-week one-test Green 흐름을 정리한 학습용 예시다. 출고표 1번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다.
입력
이전 줄의 상태와 LearnerGreen
결과·효과
관찰 상태 F15-001가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
700/300 Green은 10_000 finalState나 Q41을 증명하지 않는다
2줄F15-L02 # native exit 0과 exact JUnit tests=1/failures=0/errors=0/skipped=0을 함께 확인한다. 출고표 2번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다.
입력
1, 0, 0
결과·효과
관찰 상태 F15-002가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
Red XML과 경로를 공유하면 evidence chain이 끊긴다
3줄F15-L03 $ErrorActionPreference = 'Stop' 출고표 3번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 PowerShell 오류를 계속 진행하지 않고 중단시키는 기본 정책을 둔다.
입력
$ErrorActionPreference, 'Stop'
결과·효과
관찰 상태 F15-003가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
4줄F15-L04 $ReferenceRoot = (Resolve-Path -LiteralPath $env:FINANCIAL_IT_REFERENCE_ROOT).Path 출고표 4번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 입력 경로를 실제 절대 경로로 확인한다.
입력
$ReferenceRoot, $env
결과·효과
관찰 상태 F15-004가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
5줄F15-L05 $LearnerRoot = (Resolve-Path -LiteralPath $env:FINANCIAL_IT_LEARNER_ROOT).Path 출고표 5번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 입력 경로를 실제 절대 경로로 확인한다.
입력
$LearnerRoot, $env
결과·효과
관찰 상태 F15-005가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
6줄F15-L06 if ([string]::Equals($ReferenceRoot, $LearnerRoot, [StringComparison]::OrdinalIgnoreCase)) { 출고표 6번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 조건·반복·함수의 실행 block을 연다.
입력
$ReferenceRoot, $LearnerRoot
결과·효과
관찰 상태 F15-006가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
700/300 Green은 10_000 finalState나 Q41을 증명하지 않는다
7줄F15-L07 throw 'reference and learner roots must be different' 출고표 7번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
입력
이전 줄의 상태와 LearnerGreen
결과·효과
관찰 상태 F15-007가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
Red XML과 경로를 공유하면 evidence chain이 끊긴다
8줄F15-L08 } 출고표 8번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
입력
이전 줄의 상태와 LearnerGreen
결과·효과
관찰 상태 F15-008가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
10줄F15-L10 $Verifier = Join-Path $ReferenceRoot 'scripts\verify-track-learner-proof.ps1' 출고표 10번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
입력
$Verifier, $ReferenceRoot, 'scripts\verify-track-learner-proof.ps1'
결과·효과
관찰 상태 F15-010가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
11줄F15-L11 & powershell.exe -NoProfile -ExecutionPolicy Bypass -File $Verifier ` 출고표 11번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 W25-D5-record-green.ps1의 다음 검증 또는 설명 단계를 구성한다.
입력
$Verifier
결과·효과
관찰 상태 F15-011가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
700/300 Green은 10_000 finalState나 Q41을 증명하지 않는다
12줄F15-L12 -ReferenceRoot $ReferenceRoot -LearnerRoot $LearnerRoot -Week 25 -Phase RecordGreen -TimeoutSeconds 1200 출고표 12번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 현재 W25 selector 하나를 실행해 exact Green을 기록하는 phase다.
입력
$ReferenceRoot, $LearnerRoot, 25
결과·효과
관찰 상태 F15-012가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
Red XML과 경로를 공유하면 evidence chain이 끊긴다
13줄F15-L13 if ($LASTEXITCODE -ne 0) { throw "W25 RecordGreen wrapper exit=$LASTEXITCODE" } 출고표 13번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 현재 W25 selector 하나를 실행해 exact Green을 기록하는 phase다.
입력
$LASTEXITCODE, 0, $LASTEXITCODE
결과·효과
관찰 상태 F15-013가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
15줄F15-L15 $State = Get-Content -Raw -LiteralPath (Join-Path $LearnerRoot '.track-learning-stage.json') | ConvertFrom-Json 출고표 15번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 JSON text를 필드로 접근 가능한 PowerShell object로 바꾼다.
입력
$State, $LearnerRoot, '.track-learning-stage.json'
결과·효과
관찰 상태 F15-015가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
16줄F15-L16 $Entry = @($State.history)[-1] 출고표 16번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
입력
$Entry, $State, 1
결과·효과
관찰 상태 F15-016가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
700/300 Green은 10_000 finalState나 Q41을 증명하지 않는다
17줄F15-L17 $Suites = @($Entry.execution.suites) 출고표 17번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
입력
$Suites, $Entry
결과·효과
관찰 상태 F15-017가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
Red XML과 경로를 공유하면 evidence chain이 끊긴다
18줄F15-L18 if ($State.phase -cne 'LearnerGreen' -or $Entry.execution.mode -cne 'Green') { throw 'LearnerGreen state mismatch' } 출고표 18번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
입력
$State, 'LearnerGreen', $Entry
결과·효과
관찰 상태 F15-018가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
19줄F15-L19 if ($Entry.execution.nativeExit -ne 0 -or $Suites.Count -ne 1) { throw 'Green must have exit 0 and one suite' } 출고표 19번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
입력
$Entry, 0, $Suites
결과·효과
관찰 상태 F15-019가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
20줄F15-L20 $Suite = $Suites[0] 출고표 20번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
입력
$Suite, $Suites, 0
결과·효과
관찰 상태 F15-020가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
21줄F15-L21 if ($Suite.tests -ne 1 -or $Suite.failures -ne 0 -or $Suite.errors -ne 0 -or $Suite.skipped -ne 0) { 출고표 21번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 조건·반복·함수의 실행 block을 연다.
입력
$Suite, 1, $Suite
결과·효과
관찰 상태 F15-021가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
700/300 Green은 10_000 finalState나 Q41을 증명하지 않는다
22줄F15-L22 throw 'Green XML must be tests=1, failures=0, errors=0, skipped=0' 출고표 22번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
입력
1, 0, 0
결과·효과
관찰 상태 F15-022가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
Red XML과 경로를 공유하면 evidence chain이 끊긴다
23줄F15-L23 } 출고표 23번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
입력
이전 줄의 상태와 LearnerGreen
결과·효과
관찰 상태 F15-023가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
24줄F15-L24 $Xml = Join-Path $LearnerRoot ("build\test-results\test\TEST-{0}.xml" -f $Suite.selector) 출고표 24번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
입력
$Xml, $LearnerRoot, "build\test-results\test\TEST-{0}.xml"
결과·효과
관찰 상태 F15-024가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
25줄F15-L25 $ArchiveDir = Join-Path $LearnerRoot ("evidence\w25\{0}" -f $State.track.ToLowerInvariant()) 출고표 25번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
입력
$ArchiveDir, $LearnerRoot, "evidence\w25\{0}"
결과·효과
관찰 상태 F15-025가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
26줄F15-L26 New-Item -ItemType Directory -Force -Path $ArchiveDir | Out-Null 출고표 26번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 Markdown 표 또는 PowerShell pipeline에서 값을 열이나 다음 명령으로 연결한다.
입력
$ArchiveDir
결과·효과
관찰 상태 F15-026가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
700/300 Green은 10_000 finalState나 Q41을 증명하지 않는다
27줄F15-L27 $Archive = Join-Path $ArchiveDir 'green-exact.xml' 출고표 27번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 덮어쓰기 전에 Green JUnit XML bytes를 고유 evidence 경로로 보존한다.
입력
$Archive, $ArchiveDir, 'green-exact.xml'
결과·효과
관찰 상태 F15-027가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
Red XML과 경로를 공유하면 evidence chain이 끊긴다
28줄F15-L28 $Tmp = "$Archive.tmp" 출고표 28번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
입력
$Tmp, "$Archive.tmp"
결과·효과
관찰 상태 F15-028가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
29줄F15-L29 Copy-Item -LiteralPath $Xml -Destination $Tmp -Force 출고표 29번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 W25-D5-record-green.ps1의 다음 검증 또는 설명 단계를 구성한다.
입력
$Xml, $Tmp
결과·효과
관찰 상태 F15-029가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
30줄F15-L30 $ArchiveHash = (Get-FileHash -LiteralPath $Tmp -Algorithm SHA256).Hash.ToLowerInvariant() 출고표 30번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 현재 bytes를 64자리 digest로 evidence에 결박한다.
입력
$ArchiveHash, $Tmp
결과·효과
관찰 상태 F15-030가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
31줄F15-L31 if ($ArchiveHash -cne $Suite.xmlSha256) { throw 'archived Green XML hash differs from runtime history' } 출고표 31번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 현재 bytes를 64자리 digest로 evidence에 결박한다.
입력
$ArchiveHash, $Suite
결과·효과
관찰 상태 F15-031가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
700/300 Green은 10_000 finalState나 Q41을 증명하지 않는다
32줄F15-L32 Move-Item -LiteralPath $Tmp -Destination $Archive -Force 출고표 32번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 W25-D5-record-green.ps1의 다음 검증 또는 설명 단계를 구성한다.
입력
$Tmp, $Archive
결과·효과
관찰 상태 F15-032가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
Red XML과 경로를 공유하면 evidence chain이 끊긴다
33줄F15-L33 "W25_CURRENT_GREEN_VERIFIED track=$($State.track) tests=1 failures=0 errors=0 skipped=0 archived_xml_sha256=$ArchiveHash" 출고표 33번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 현재 bytes를 64자리 digest로 evidence에 결박한다.
입력
$State, 1, 0
결과·효과
관찰 상태 F15-033가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
05

STEP 05 / 13

원본 코드 조각

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

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

F15-C01 · 원문 1–12줄1–12줄
1–12줄 원본
# 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
F15-C02 · 원문 13–24줄13–24줄
13–24줄 원본
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)
F15-C03 · 원문 25–33줄25–33줄
25–33줄 원본
$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"
06

STEP 06 / 13

코드 한 줄씩 한국어로 번역

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

전체 번역 31 / 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실행 의미: 입력 경로를 실제 절대 경로로 확인한다.
6if ([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다.
13if ($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 변수에 저장한다.
18if ($State.phase -cne 'LearnerGreen' -or $Entry.execution.mode -cne 'Green') { throw 'LearnerGreen state mismatch' }실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
19if ($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 변수에 저장한다.
21if ($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 변수에 저장한다.
26New-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 변수에 저장한다.
29Copy-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에 결박한다.
31if ($ArchiveHash -cne $Suite.xmlSha256) { throw 'archived Green XML hash differs from runtime history' }실행 의미: 현재 bytes를 64자리 digest로 evidence에 결박한다.
32Move-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에 결박한다.
07

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를 서로 대체하지 않는다.

실행 순서

  1. 기본 트랙은 SECURITIES(증권)이며, 명시적 CARD 선택은 기본값을 덮어쓴다. 실제 실행 전 최종 선택 한 개를 selected-track.csv·근거·state에 같은 값으로 기록하고 서로 다른 reference/learner root를 확인한다.
  2. Prepare→VerifyStarter→RecordRed→VerifySolution→RecordGreen→Cumulative→Review 순서를 지킨다.
  3. test를 소유한 세 phase에서만 native exit와 exact JUnit XML 수치를 판정한다.
  4. 다음 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히토리 → 니지카 → 료 → 키타
  1. 히토리

    nativeExit=0가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 native 0·tests=1·failure/error/skip=0을 확인하고 Green XML bytes를 history hash와 결박해 보존한다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘Red XML과 경로를 공유하면 evidence chain이 끊긴다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 nativeExit=0와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

08

STEP 08 / 13

실제 값 따라가기

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

순서들어온 값코드가 하는 일나온 값·상태경계
입력LearnerGreensource 계약에 대입F15 실행/설명 시작 상태700/300 Green은 10_000 finalState나 Q41을 증명하지 않는다
검증nativeExit=0expected와 actual 또는 형식 대조통과 또는 첫 mismatchRed XML과 경로를 공유하면 evidence chain이 끊긴다
증거green-exact.xmlmarker·hash·row를 같은 run에 연결범위가 적힌 evidence 후보이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
실제 값 — D5 RecordGreen — current selector exact Green과 XML archive히토리 → 니지카 → 료 → 키타
  1. 히토리

    tests=1가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 native 0·tests=1·failure/error/skip=0을 확인하고 Green XML bytes를 history hash와 결박해 보존한다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘reference와 learner root는 서로 달라야 한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 tests=1와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

09

STEP 09 / 13

Gradle·JUnit XML·PowerShell·SQL 내부에서 벌어지는 일

세 test phase, XML bytes archive, Review, 별도 Q41, USER_ATTESTED sealed 결과의 owner와 증명 범위를 구분합니다.

source/contract

W25-D5-record-green.ps1 bytes와 track·phase·hash 계약을 읽는다.

SECURITIES 기본 선택과 파일 존재·phase 이름만으로 runtime Green을 주장할 수 없다. 실제 selected-track evidence와 실행 결과는 별도다.
execution/evidence

RecordRed·RecordGreen·Cumulative에서만 native exit와 exact JUnit XML을 만든다.

700/300 Green은 10_000 finalState나 Q41을 증명하지 않는다
retention/review

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히토리 → 니지카 → 료 → 키타
  1. 히토리

    status totals=0가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 native 0·tests=1·failure/error/skip=0을 확인하고 Green XML bytes를 history hash와 결박해 보존한다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 status totals=0와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

10

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이 생기지 않는다.

11

STEP 11 / 13

이 코드가 보장하지 않는 것

선택 미결정·10_000 finalState·XML 보존·Review/Q41/sealed official truth처럼 이 코드가 책임지지 않는 일을 분리합니다.

증명 범위

700/300 Green은 10_000 finalState나 Q41을 증명하지 않는다

이 책임을 맡는 곳: runtime Gate
증명 범위

Red XML과 경로를 공유하면 evidence chain이 끊긴다

이 책임을 맡는 곳: external/human review
증명 범위

reference와 learner root는 서로 달라야 한다

이 책임을 맡는 곳: release manifest
증명 범위

기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다

이 책임을 맡는 곳: 운영 환경
증명하지 않는 범위 — D5 RecordGreen — current selector exact Green과 XML archive히토리 → 니지카 → 료 → 키타
  1. 히토리

    green-exact.xml가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 native 0·tests=1·failure/error/skip=0을 확인하고 Green XML bytes를 history hash와 결박해 보존한다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 green-exact.xml와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

12

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. 1. 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다
  2. 2. 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다
  3. 3. PowerShell 오류를 계속 진행하지 않고 중단시키는 기본 정책을 둔다
  4. 4. 입력 경로를 실제 절대 경로로 확인한다
  5. 5. 입력 경로를 실제 절대 경로로 확인한다
  6. 6. 조건·반복·함수의 실행 block을 연다
  7. 7. 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다
  8. 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 책임을 설명할 수 있나?
13

STEP 13 / 13

전체 원본 source

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

학습용 예시 전체 확인하기 · 정본 답안 아님 · NOT_RUN
학습용 예시 · W25 phase wrapper · 정본 답안 아님 · 로컬 미실행illustrative/powershell/W25-D5-record-green.ps1SHA-256 f09927dc38426d39345ac3392d927beb910700aa5cf9cea93514f21a9fbb3dbe
D5 RecordGreen — current selector exact Green과 XML archive 전체
# 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"
16

W25-SQL-Q41 — balance snapshot과 opening 포함 ledger sum 대사

illustrative/sql/W25-SQL-Q41.sql

학습용 예시 · W25-SQL-Q41 prompt 기반 · 정본 답안 아님 · workbook 제공 정답 아님 · 학습용 예시 · 정본 답안 아님 · NOT_RUN · W25-F16
30줄 연결30줄 번역3 chunks
01

STEP 01 / 13

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

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

오늘의 한 문장

account 한 행과 opening entry를 포함한 ledger_entry 합계를 계좌별로 비교해 mismatch 계좌만 반환하는 학습용 query를 보여 준다.

  1. account grain은 어느 source와 실제 결과에서 확인해야 할까?
  2. 첫 실패를 만드는 조건과 fail-closed 지점은 어디일까?
  3. 왜 ‘PDF는 prompt만 주며 workbook 제공 정답이 아니다’를 별도 경계로 남겨야 할까?
이 파일에서 끝까지 다시 쓰는 값account grainSUM(signed_amount)LEFT JOINCOALESCE(...,0)current fixture expected rows=2
왜 필요한가 — W25-SQL-Q41 — balance snapshot과 opening 포함 ledger sum 대사히토리 → 니지카 → 료 → 키타
  1. 히토리

    account grain가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 account 한 행과 opening entry를 포함한 ledger_entry 합계를 계좌별로 비교해 mismatch 계좌만 반환하는 학습용 query를 보여 준다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘PDF는 prompt만 주며 workbook 제공 정답이 아니다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 account grain와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

02

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 확인을 대신하지 않는다.

03

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이며 실제 실행은 정확히 한 트랙에만 귀속한다
04

STEP 04 / 13

비유 ↔ 코드 전체 연결표

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

단어 몇 개만 뽑은 표가 아닙니다.학습용 예시 · W25-SQL-Q41 prompt 기반 · 정본 답안 아님 · workbook 제공 정답 아님에서 비어 있지 않은 모든 줄을 원본 줄 번호 그대로 연결했습니다.30 / 30 연결
정확한 원본 줄STARRY 비유실제 뜻·입력·결과·한계
1줄F16-L01 -- W25-SQL-Q41 학습용 예시이며 workbook 제공 정답이 아니다. 출고표 1번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 W25-SQL-Q41.sql의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 account grain
결과·효과
관찰 상태 F16-001가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
PDF는 prompt만 주며 workbook 제공 정답이 아니다
2줄F16-L02 -- 입력 grain: account 한 행은 계좌 snapshot, ledger_entry 한 행은 원장 증감 한 건이다. 출고표 2번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 W25-SQL-Q41.sql의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 account grain
결과·효과
관찰 상태 F16-002가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
RecordGreen runtime은 PostgreSQL/Q41을 실행하지 않는다
3줄F16-L03 -- 출력 grain: snapshot과 opening 포함 원장 합계가 다른 계좌 한 행. 현재 fixture 예상 행 수는 2다. 출고표 3번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 W25-SQL-Q41.sql의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 account grain
결과·효과
관찰 상태 F16-003가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
실제 psql transcript/hash가 별도 필요하다
4줄F16-L04 WITH ledger_by_account AS ( 출고표 4번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 opening entry를 포함한 원장 증감액을 계좌별로 먼저 합산한다.
입력
이전 줄의 상태와 account grain
결과·효과
관찰 상태 F16-004가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
5줄F16-L05 SELECT 출고표 5번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 SQL 집합의 입력·변환·필터 단계를 선언한다.
입력
이전 줄의 상태와 account grain
결과·효과
관찰 상태 F16-005가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
6줄F16-L06 le.account_id, 출고표 6번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 W25-SQL-Q41.sql의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 account grain
결과·효과
관찰 상태 F16-006가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
7줄F16-L07 SUM(le.signed_amount) AS ledger_sum 출고표 7번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 W25-SQL-Q41.sql의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 account grain
결과·효과
관찰 상태 F16-007가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
PDF는 prompt만 주며 workbook 제공 정답이 아니다
8줄F16-L08 FROM ledger_entry AS le 출고표 8번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 SQL 집합의 입력·변환·필터 단계를 선언한다.
입력
이전 줄의 상태와 account grain
결과·효과
관찰 상태 F16-008가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
RecordGreen runtime은 PostgreSQL/Q41을 실행하지 않는다
9줄F16-L09 GROUP BY le.account_id 출고표 9번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 W25-SQL-Q41.sql의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 account grain
결과·효과
관찰 상태 F16-009가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
실제 psql transcript/hash가 별도 필요하다
10줄F16-L10 ), 출고표 10번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 W25-SQL-Q41.sql의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 account grain
결과·효과
관찰 상태 F16-010가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
11줄F16-L11 reconciled AS ( 출고표 11번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 W25-SQL-Q41.sql의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 account grain
결과·효과
관찰 상태 F16-011가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
12줄F16-L12 SELECT 출고표 12번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 SQL 집합의 입력·변환·필터 단계를 선언한다.
입력
이전 줄의 상태와 account grain
결과·효과
관찰 상태 F16-012가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
13줄F16-L13 a.account_id, 출고표 13번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 W25-SQL-Q41.sql의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 account grain
결과·효과
관찰 상태 F16-013가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
PDF는 prompt만 주며 workbook 제공 정답이 아니다
14줄F16-L14 a.balance AS snapshot_balance, 출고표 14번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 W25-SQL-Q41.sql의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 account grain
결과·효과
관찰 상태 F16-014가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
RecordGreen runtime은 PostgreSQL/Q41을 실행하지 않는다
15줄F16-L15 COALESCE(l.ledger_sum, 0) AS ledger_sum, 출고표 15번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 원장 행이 없는 계좌의 합계를 0으로 바꾸어 LEFT JOIN 결과를 보존한다.
입력
0
결과·효과
관찰 상태 F16-015가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
실제 psql transcript/hash가 별도 필요하다
16줄F16-L16 a.balance - COALESCE(l.ledger_sum, 0) AS difference 출고표 16번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 원장 행이 없는 계좌의 합계를 0으로 바꾸어 LEFT JOIN 결과를 보존한다.
입력
0
결과·효과
관찰 상태 F16-016가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
17줄F16-L17 FROM account AS a 출고표 17번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 SQL 집합의 입력·변환·필터 단계를 선언한다.
입력
이전 줄의 상태와 account grain
결과·효과
관찰 상태 F16-017가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
18줄F16-L18 LEFT JOIN ledger_by_account AS l 출고표 18번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 opening entry를 포함한 원장 증감액을 계좌별로 먼저 합산한다.
입력
이전 줄의 상태와 account grain
결과·효과
관찰 상태 F16-018가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
19줄F16-L19 ON l.account_id = a.account_id 출고표 19번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 W25-SQL-Q41.sql의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 account grain
결과·효과
관찰 상태 F16-019가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
PDF는 prompt만 주며 workbook 제공 정답이 아니다
20줄F16-L20 ) 출고표 20번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
입력
이전 줄의 상태와 account grain
결과·효과
관찰 상태 F16-020가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
RecordGreen runtime은 PostgreSQL/Q41을 실행하지 않는다
21줄F16-L21 SELECT 출고표 21번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 SQL 집합의 입력·변환·필터 단계를 선언한다.
입력
이전 줄의 상태와 account grain
결과·효과
관찰 상태 F16-021가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
실제 psql transcript/hash가 별도 필요하다
22줄F16-L22 account_id, 출고표 22번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 W25-SQL-Q41.sql의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 account grain
결과·효과
관찰 상태 F16-022가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
23줄F16-L23 snapshot_balance, 출고표 23번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 W25-SQL-Q41.sql의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 account grain
결과·효과
관찰 상태 F16-023가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
24줄F16-L24 ledger_sum, 출고표 24번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 W25-SQL-Q41.sql의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 account grain
결과·효과
관찰 상태 F16-024가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
25줄F16-L25 difference 출고표 25번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 W25-SQL-Q41.sql의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 account grain
결과·효과
관찰 상태 F16-025가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
PDF는 prompt만 주며 workbook 제공 정답이 아니다
26줄F16-L26 FROM reconciled 출고표 26번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 SQL 집합의 입력·변환·필터 단계를 선언한다.
입력
이전 줄의 상태와 account grain
결과·효과
관찰 상태 F16-026가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
RecordGreen runtime은 PostgreSQL/Q41을 실행하지 않는다
27줄F16-L27 WHERE difference <> 0 출고표 27번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 SQL 집합의 입력·변환·필터 단계를 선언한다.
입력
0
결과·효과
관찰 상태 F16-027가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
실제 psql transcript/hash가 별도 필요하다
28줄F16-L28 ORDER BY account_id; 출고표 28번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 출력 또는 window 계산 순서를 안정적으로 정한다.
입력
이전 줄의 상태와 account grain
결과·효과
관찰 상태 F16-028가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
30줄F16-L30 -- opening entry 반례: opening을 제외하면 정상 계좌도 거짓 mismatch가 된다. 출고표 30번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 W25-SQL-Q41.sql의 다음 검증 또는 설명 단계를 구성한다.
입력
이전 줄의 상태와 account grain
결과·효과
관찰 상태 F16-030가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
31줄F16-L31 -- 원장 0건 반례: LEFT JOIN과 COALESCE로 balance=0 계좌는 difference=0, 양수 snapshot은 mismatch로 남는다. 출고표 31번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 원장 행이 없는 계좌의 합계를 0으로 바꾸어 LEFT JOIN 결과를 보존한다.
입력
0, 0
결과·효과
관찰 상태 F16-031가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
PDF는 prompt만 주며 workbook 제공 정답이 아니다
05

STEP 05 / 13

원본 코드 조각

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

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

F16-C01 · 원문 1–12줄1–12줄
1–12줄 원본
-- 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
F16-C02 · 원문 13–24줄13–24줄
13–24줄 원본
    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,
F16-C03 · 원문 25–31줄25–31줄
25–31줄 원본
  difference
FROM reconciled
WHERE difference <> 0
ORDER BY account_id;

-- opening entry 반례: opening을 제외하면 정상 계좌도 거짓 mismatch가 된다.
-- 원장 0건 반례: LEFT JOIN과 COALESCE로 balance=0 계좌는 difference=0, 양수 snapshot은 mismatch로 남는다.
06

STEP 06 / 13

코드 한 줄씩 한국어로 번역

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

전체 번역 30 / 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의 다음 검증 또는 설명 단계를 구성한다.
4WITH 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의 다음 검증 또는 설명 단계를 구성한다.
11reconciled 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 또는 호출 범위를 닫는다.
21SELECT실행 의미: 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의 다음 검증 또는 설명 단계를 구성한다.
26FROM reconciled실행 의미: SQL 집합의 입력·변환·필터 단계를 선언한다.
27WHERE difference <> 0실행 의미: SQL 집합의 입력·변환·필터 단계를 선언한다.
28ORDER 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 결과를 보존한다.
07

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를 서로 대체하지 않는다.

실행 순서

  1. 기본 트랙은 SECURITIES(증권)이며, 명시적 CARD 선택은 기본값을 덮어쓴다. 실제 실행 전 최종 선택 한 개를 selected-track.csv·근거·state에 같은 값으로 기록하고 서로 다른 reference/learner root를 확인한다.
  2. Prepare→VerifyStarter→RecordRed→VerifySolution→RecordGreen→Cumulative→Review 순서를 지킨다.
  3. test를 소유한 세 phase에서만 native exit와 exact JUnit XML 수치를 판정한다.
  4. 다음 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 대사히토리 → 니지카 → 료 → 키타
  1. 히토리

    SUM(signed_amount)가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 account 한 행과 opening entry를 포함한 ledger_entry 합계를 계좌별로 비교해 mismatch 계좌만 반환하는 학습용 query를 보여 준다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘RecordGreen runtime은 PostgreSQL/Q41을 실행하지 않는다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 SUM(signed_amount)와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

08

STEP 08 / 13

실제 값 따라가기

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

순서들어온 값코드가 하는 일나온 값·상태경계
입력account grainsource 계약에 대입F16 실행/설명 시작 상태PDF는 prompt만 주며 workbook 제공 정답이 아니다
검증SUM(signed_amount)expected와 actual 또는 형식 대조통과 또는 첫 mismatchRecordGreen runtime은 PostgreSQL/Q41을 실행하지 않는다
증거current fixture expected rows=2marker·hash·row를 같은 run에 연결범위가 적힌 evidence 후보이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
실제 값 — W25-SQL-Q41 — balance snapshot과 opening 포함 ledger sum 대사히토리 → 니지카 → 료 → 키타
  1. 히토리

    LEFT JOIN가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 account 한 행과 opening entry를 포함한 ledger_entry 합계를 계좌별로 비교해 mismatch 계좌만 반환하는 학습용 query를 보여 준다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘실제 psql transcript/hash가 별도 필요하다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 LEFT JOIN와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

09

STEP 09 / 13

Gradle·JUnit XML·PowerShell·SQL 내부에서 벌어지는 일

세 test phase, XML bytes archive, Review, 별도 Q41, USER_ATTESTED sealed 결과의 owner와 증명 범위를 구분합니다.

source/contract

W25-SQL-Q41.sql bytes와 track·phase·hash 계약을 읽는다.

SECURITIES 기본 선택과 파일 존재·phase 이름만으로 runtime Green을 주장할 수 없다. 실제 selected-track evidence와 실행 결과는 별도다.
execution/evidence

RecordRed·RecordGreen·Cumulative에서만 native exit와 exact JUnit XML을 만든다.

PDF는 prompt만 주며 workbook 제공 정답이 아니다
retention/review

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 대사히토리 → 니지카 → 료 → 키타
  1. 히토리

    COALESCE(...,0)가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 account 한 행과 opening entry를 포함한 ledger_entry 합계를 계좌별로 비교해 mismatch 계좌만 반환하는 학습용 query를 보여 준다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘reference와 learner root는 서로 달라야 한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 COALESCE(...,0)와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

10

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이 생기지 않는다.

11

STEP 11 / 13

이 코드가 보장하지 않는 것

선택 미결정·10_000 finalState·XML 보존·Review/Q41/sealed official truth처럼 이 코드가 책임지지 않는 일을 분리합니다.

증명 범위

PDF는 prompt만 주며 workbook 제공 정답이 아니다

이 책임을 맡는 곳: runtime Gate
증명 범위

RecordGreen runtime은 PostgreSQL/Q41을 실행하지 않는다

이 책임을 맡는 곳: external/human review
증명 범위

실제 psql transcript/hash가 별도 필요하다

이 책임을 맡는 곳: release manifest
증명 범위

reference와 learner root는 서로 달라야 한다

이 책임을 맡는 곳: 운영 환경
증명하지 않는 범위 — W25-SQL-Q41 — balance snapshot과 opening 포함 ledger sum 대사히토리 → 니지카 → 료 → 키타
  1. 히토리

    current fixture expected rows=2가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 account 한 행과 opening entry를 포함한 ledger_entry 합계를 계좌별로 비교해 mismatch 계좌만 반환하는 학습용 query를 보여 준다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 current fixture expected rows=2와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

12

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. 1. W25-SQL-Q41.sql의 다음 검증 또는 설명 단계를 구성한다
  2. 2. W25-SQL-Q41.sql의 다음 검증 또는 설명 단계를 구성한다
  3. 3. W25-SQL-Q41.sql의 다음 검증 또는 설명 단계를 구성한다
  4. 4. opening entry를 포함한 원장 증감액을 계좌별로 먼저 합산한다
  5. 5. SQL 집합의 입력·변환·필터 단계를 선언한다
  6. 6. W25-SQL-Q41.sql의 다음 검증 또는 설명 단계를 구성한다
  7. 7. W25-SQL-Q41.sql의 다음 검증 또는 설명 단계를 구성한다
  8. 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 책임을 설명할 수 있나?
13

STEP 13 / 13

전체 원본 source

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

학습용 예시 전체 확인하기 · 정본 답안 아님 · NOT_RUN
학습용 예시 · W25-SQL-Q41 prompt 기반 · 정본 답안 아님 · workbook 제공 정답 아님illustrative/sql/W25-SQL-Q41.sqlSHA-256 d6425d56f370aa51762a4c2dd7da7a7956de00e0258d18ac8d575a98e22d78f8
W25-SQL-Q41 — balance snapshot과 opening 포함 ledger sum 대사 전체
-- 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로 남는다.
17

D6 Cumulative — W25 selectorCount=1 누적 Green

illustrative/powershell/W25-D6-cumulative.ps1

학습용 예시 · W25 phase wrapper · 정본 답안 아님 · 로컬 미실행 · 학습용 예시 · 정본 답안 아님 · NOT_RUN · W25-F17
37줄 연결37줄 번역4 chunks
01

STEP 01 / 13

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

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

오늘의 한 문장

선택 트랙의 W25..현재 selector를 누적 실행하고 첫 트랙 주차인 W25에서 exactly one suite Green과 XML archive를 확인한다.

  1. CumulativeGreen은 어느 source와 실제 결과에서 확인해야 할까?
  2. 첫 실패를 만드는 조건과 fail-closed 지점은 어디일까?
  3. 왜 ‘미선택 branch와 미래 주차는 누적 claim이 아니다’를 별도 경계로 남겨야 할까?
이 파일에서 끝까지 다시 쓰는 값CumulativeGreenselectorCount=1tests=1status totals=0cumulative-exact.xml
왜 필요한가 — D6 Cumulative — W25 selectorCount=1 누적 Green히토리 → 니지카 → 료 → 키타
  1. 히토리

    CumulativeGreen가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 선택 트랙의 W25..현재 selector를 누적 실행하고 첫 트랙 주차인 W25에서 exactly one suite Green과 XML archive를 확인한다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘미선택 branch와 미래 주차는 누적 claim이 아니다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 CumulativeGreen와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

02

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 확인을 대신하지 않는다.

03

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을 실행하지 않았다
04

STEP 04 / 13

비유 ↔ 코드 전체 연결표

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

단어 몇 개만 뽑은 표가 아닙니다.학습용 예시 · W25 phase wrapper · 정본 답안 아님 · 로컬 미실행에서 비어 있지 않은 모든 줄을 원본 줄 번호 그대로 연결했습니다.37 / 37 연결
정확한 원본 줄STARRY 비유실제 뜻·입력·결과·한계
1줄F17-L01 # W25 PDF p38-p47의 W25부터 현재까지 누적 Green 흐름을 정리한 학습용 예시다. 출고표 1번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다.
입력
이전 줄의 상태와 CumulativeGreen
결과·효과
관찰 상태 F17-001가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
미선택 branch와 미래 주차는 누적 claim이 아니다
2줄F17-L02 # W25는 첫 트랙 주차이므로 selectorCount=1이지만 이후 주차에는 누적 selector 수가 증가한다. 출고표 2번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 W25 첫 트랙 주차의 누적 selector 수가 정확히 1인지 확인한다.
입력
이전 줄의 상태와 CumulativeGreen
결과·효과
관찰 상태 F17-002가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
cumulative log와 XML bytes는 별도 artifact다
3줄F17-L03 $ErrorActionPreference = 'Stop' 출고표 3번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 PowerShell 오류를 계속 진행하지 않고 중단시키는 기본 정책을 둔다.
입력
$ErrorActionPreference, 'Stop'
결과·효과
관찰 상태 F17-003가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
4줄F17-L04 $ReferenceRoot = (Resolve-Path -LiteralPath $env:FINANCIAL_IT_REFERENCE_ROOT).Path 출고표 4번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 입력 경로를 실제 절대 경로로 확인한다.
입력
$ReferenceRoot, $env
결과·효과
관찰 상태 F17-004가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
5줄F17-L05 $LearnerRoot = (Resolve-Path -LiteralPath $env:FINANCIAL_IT_LEARNER_ROOT).Path 출고표 5번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 입력 경로를 실제 절대 경로로 확인한다.
입력
$LearnerRoot, $env
결과·효과
관찰 상태 F17-005가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
6줄F17-L06 if ([string]::Equals($ReferenceRoot, $LearnerRoot, [StringComparison]::OrdinalIgnoreCase)) { 출고표 6번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 조건·반복·함수의 실행 block을 연다.
입력
$ReferenceRoot, $LearnerRoot
결과·효과
관찰 상태 F17-006가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
미선택 branch와 미래 주차는 누적 claim이 아니다
7줄F17-L07 throw 'reference and learner roots must be different' 출고표 7번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
입력
이전 줄의 상태와 CumulativeGreen
결과·효과
관찰 상태 F17-007가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
cumulative log와 XML bytes는 별도 artifact다
8줄F17-L08 } 출고표 8번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
입력
이전 줄의 상태와 CumulativeGreen
결과·효과
관찰 상태 F17-008가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
10줄F17-L10 $Verifier = Join-Path $ReferenceRoot 'scripts\verify-track-learner-proof.ps1' 출고표 10번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
입력
$Verifier, $ReferenceRoot, 'scripts\verify-track-learner-proof.ps1'
결과·효과
관찰 상태 F17-010가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
11줄F17-L11 & powershell.exe -NoProfile -ExecutionPolicy Bypass -File $Verifier ` 출고표 11번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 W25-D6-cumulative.ps1의 다음 검증 또는 설명 단계를 구성한다.
입력
$Verifier
결과·효과
관찰 상태 F17-011가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
미선택 branch와 미래 주차는 누적 claim이 아니다
12줄F17-L12 -ReferenceRoot $ReferenceRoot -LearnerRoot $LearnerRoot -Week 25 -Phase Cumulative -TimeoutSeconds 1200 출고표 12번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 W25부터 현재 주까지 선택 트랙 selector를 누적 실행하는 phase다.
입력
$ReferenceRoot, $LearnerRoot, 25
결과·효과
관찰 상태 F17-012가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
cumulative log와 XML bytes는 별도 artifact다
13줄F17-L13 if ($LASTEXITCODE -ne 0) { throw "W25 Cumulative wrapper exit=$LASTEXITCODE" } 출고표 13번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 W25부터 현재 주까지 선택 트랙 selector를 누적 실행하는 phase다.
입력
$LASTEXITCODE, 0, $LASTEXITCODE
결과·효과
관찰 상태 F17-013가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
15줄F17-L15 $State = Get-Content -Raw -LiteralPath (Join-Path $LearnerRoot '.track-learning-stage.json') | ConvertFrom-Json 출고표 15번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 JSON text를 필드로 접근 가능한 PowerShell object로 바꾼다.
입력
$State, $LearnerRoot, '.track-learning-stage.json'
결과·효과
관찰 상태 F17-015가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
16줄F17-L16 $Entry = @($State.history)[-1] 출고표 16번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
입력
$Entry, $State, 1
결과·효과
관찰 상태 F17-016가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
미선택 branch와 미래 주차는 누적 claim이 아니다
17줄F17-L17 $Suites = @($Entry.execution.suites) 출고표 17번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
입력
$Suites, $Entry
결과·효과
관찰 상태 F17-017가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
cumulative log와 XML bytes는 별도 artifact다
18줄F17-L18 if ($State.phase -cne 'CumulativeGreen' -or $Entry.execution.mode -cne 'Cumulative') { 출고표 18번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 W25부터 현재 주까지 선택 트랙 selector를 누적 실행하는 phase다.
입력
$State, 'CumulativeGreen', $Entry
결과·효과
관찰 상태 F17-018가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
19줄F17-L19 throw 'CumulativeGreen state mismatch' 출고표 19번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 W25부터 현재 주까지 선택 트랙 selector를 누적 실행하는 phase다.
입력
'CumulativeGreen state mismatch'
결과·효과
관찰 상태 F17-019가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
20줄F17-L20 } 출고표 20번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
입력
이전 줄의 상태와 CumulativeGreen
결과·효과
관찰 상태 F17-020가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
21줄F17-L21 if ($Entry.selectorCount -ne 1 -or $Suites.Count -ne 1 -or $Entry.execution.nativeExit -ne 0) { 출고표 21번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 W25 첫 트랙 주차의 누적 selector 수가 정확히 1인지 확인한다.
입력
$Entry, 1, $Suites
결과·효과
관찰 상태 F17-021가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
미선택 branch와 미래 주차는 누적 claim이 아니다
22줄F17-L22 throw 'W25 cumulative inventory must contain exactly one Green selector' 출고표 22번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 W25부터 현재 주까지 선택 트랙 selector를 누적 실행하는 phase다.
입력
이전 줄의 상태와 CumulativeGreen
결과·효과
관찰 상태 F17-022가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
cumulative log와 XML bytes는 별도 artifact다
23줄F17-L23 } 출고표 23번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
입력
이전 줄의 상태와 CumulativeGreen
결과·효과
관찰 상태 F17-023가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
24줄F17-L24 foreach ($Suite in $Suites) { 출고표 24번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 고정 목록의 각 항목에 같은 검사를 반복 적용한다.
입력
$Suite, $Suites
결과·효과
관찰 상태 F17-024가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
25줄F17-L25 if ($Suite.tests -ne 1 -or $Suite.failures -ne 0 -or $Suite.errors -ne 0 -or $Suite.skipped -ne 0) { 출고표 25번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 조건·반복·함수의 실행 block을 연다.
입력
$Suite, 1, $Suite
결과·효과
관찰 상태 F17-025가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
26줄F17-L26 throw "cumulative suite mismatch: $($Suite.class)" 출고표 26번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 W25부터 현재 주까지 선택 트랙 selector를 누적 실행하는 phase다.
입력
$Suite
결과·효과
관찰 상태 F17-026가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
미선택 branch와 미래 주차는 누적 claim이 아니다
27줄F17-L27 } 출고표 27번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
입력
이전 줄의 상태와 CumulativeGreen
결과·효과
관찰 상태 F17-027가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
cumulative log와 XML bytes는 별도 artifact다
28줄F17-L28 } 출고표 28번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
입력
이전 줄의 상태와 CumulativeGreen
결과·효과
관찰 상태 F17-028가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
29줄F17-L29 $Suite = $Suites[0] 출고표 29번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
입력
$Suite, $Suites, 0
결과·효과
관찰 상태 F17-029가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
30줄F17-L30 $Xml = Join-Path $LearnerRoot ("build\test-results\test\TEST-{0}.xml" -f $Suite.selector) 출고표 30번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
입력
$Xml, $LearnerRoot, "build\test-results\test\TEST-{0}.xml"
결과·효과
관찰 상태 F17-030가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
31줄F17-L31 $ArchiveDir = Join-Path $LearnerRoot ("evidence\w25\{0}" -f $State.track.ToLowerInvariant()) 출고표 31번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
입력
$ArchiveDir, $LearnerRoot, "evidence\w25\{0}"
결과·효과
관찰 상태 F17-031가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
미선택 branch와 미래 주차는 누적 claim이 아니다
32줄F17-L32 New-Item -ItemType Directory -Force -Path $ArchiveDir | Out-Null 출고표 32번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 Markdown 표 또는 PowerShell pipeline에서 값을 열이나 다음 명령으로 연결한다.
입력
$ArchiveDir
결과·효과
관찰 상태 F17-032가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
cumulative log와 XML bytes는 별도 artifact다
33줄F17-L33 $Archive = Join-Path $ArchiveDir 'cumulative-exact.xml' 출고표 33번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 W25부터 현재 주까지 선택 트랙 selector를 누적 실행하는 phase다.
입력
$Archive, $ArchiveDir, 'cumulative-exact.xml'
결과·효과
관찰 상태 F17-033가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
34줄F17-L34 $Tmp = "$Archive.tmp" 출고표 34번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
입력
$Tmp, "$Archive.tmp"
결과·효과
관찰 상태 F17-034가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
35줄F17-L35 Copy-Item -LiteralPath $Xml -Destination $Tmp -Force 출고표 35번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 W25-D6-cumulative.ps1의 다음 검증 또는 설명 단계를 구성한다.
입력
$Xml, $Tmp
결과·효과
관찰 상태 F17-035가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
36줄F17-L36 $ArchiveHash = (Get-FileHash -LiteralPath $Tmp -Algorithm SHA256).Hash.ToLowerInvariant() 출고표 36번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 현재 bytes를 64자리 digest로 evidence에 결박한다.
입력
$ArchiveHash, $Tmp
결과·효과
관찰 상태 F17-036가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
미선택 branch와 미래 주차는 누적 claim이 아니다
37줄F17-L37 if ($ArchiveHash -cne $Suite.xmlSha256) { throw 'archived cumulative XML hash differs from runtime history' } 출고표 37번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 W25부터 현재 주까지 선택 트랙 selector를 누적 실행하는 phase다.
입력
$ArchiveHash, $Suite
결과·효과
관찰 상태 F17-037가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
cumulative log와 XML bytes는 별도 artifact다
38줄F17-L38 Move-Item -LiteralPath $Tmp -Destination $Archive -Force 출고표 38번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 W25-D6-cumulative.ps1의 다음 검증 또는 설명 단계를 구성한다.
입력
$Tmp, $Archive
결과·효과
관찰 상태 F17-038가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
39줄F17-L39 "W25_CUMULATIVE_GREEN_VERIFIED track=$($State.track) selectors=1 tests=1 archived_xml_sha256=$ArchiveHash" 출고표 39번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 W25부터 현재 주까지 선택 트랙 selector를 누적 실행하는 phase다.
입력
$State, 1, 1
결과·효과
관찰 상태 F17-039가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
05

STEP 05 / 13

원본 코드 조각

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

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

F17-C01 · 원문 1–12줄1–12줄
1–12줄 원본
# 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
F17-C02 · 원문 13–24줄13–24줄
13–24줄 원본
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) {
F17-C03 · 원문 25–36줄25–36줄
25–36줄 원본
  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()
F17-C04 · 원문 37–39줄37–39줄
37–39줄 원본
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"
06

STEP 06 / 13

코드 한 줄씩 한국어로 번역

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

전체 번역 37 / 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실행 의미: 입력 경로를 실제 절대 경로로 확인한다.
6if ([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다.
13if ($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 변수에 저장한다.
18if ($State.phase -cne 'CumulativeGreen' -or $Entry.execution.mode -cne 'Cumulative') {실행 의미: W25부터 현재 주까지 선택 트랙 selector를 누적 실행하는 phase다.
19 throw 'CumulativeGreen state mismatch'실행 의미: W25부터 현재 주까지 선택 트랙 selector를 누적 실행하는 phase다.
20}실행 의미: 앞에서 연 block 또는 호출 범위를 닫는다.
21if ($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 또는 호출 범위를 닫는다.
24foreach ($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 변수에 저장한다.
32New-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 변수에 저장한다.
35Copy-Item -LiteralPath $Xml -Destination $Tmp -Force실행 의미: W25-D6-cumulative.ps1의 다음 검증 또는 설명 단계를 구성한다.
36$ArchiveHash = (Get-FileHash -LiteralPath $Tmp -Algorithm SHA256).Hash.ToLowerInvariant()실행 의미: 현재 bytes를 64자리 digest로 evidence에 결박한다.
37if ($ArchiveHash -cne $Suite.xmlSha256) { throw 'archived cumulative XML hash differs from runtime history' }실행 의미: W25부터 현재 주까지 선택 트랙 selector를 누적 실행하는 phase다.
38Move-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다.
07

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를 서로 대체하지 않는다.

실행 순서

  1. 기본 트랙은 SECURITIES(증권)이며, 명시적 CARD 선택은 기본값을 덮어쓴다. 실제 실행 전 최종 선택 한 개를 selected-track.csv·근거·state에 같은 값으로 기록하고 서로 다른 reference/learner root를 확인한다.
  2. Prepare→VerifyStarter→RecordRed→VerifySolution→RecordGreen→Cumulative→Review 순서를 지킨다.
  3. test를 소유한 세 phase에서만 native exit와 exact JUnit XML 수치를 판정한다.
  4. 다음 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히토리 → 니지카 → 료 → 키타
  1. 히토리

    selectorCount=1가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 선택 트랙의 W25..현재 selector를 누적 실행하고 첫 트랙 주차인 W25에서 exactly one suite Green과 XML archive를 확인한다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘cumulative log와 XML bytes는 별도 artifact다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 selectorCount=1와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

08

STEP 08 / 13

실제 값 따라가기

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

순서들어온 값코드가 하는 일나온 값·상태경계
입력CumulativeGreensource 계약에 대입F17 실행/설명 시작 상태미선택 branch와 미래 주차는 누적 claim이 아니다
검증selectorCount=1expected와 actual 또는 형식 대조통과 또는 첫 mismatchcumulative log와 XML bytes는 별도 artifact다
증거cumulative-exact.xmlmarker·hash·row를 같은 run에 연결범위가 적힌 evidence 후보이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
실제 값 — D6 Cumulative — W25 selectorCount=1 누적 Green히토리 → 니지카 → 료 → 키타
  1. 히토리

    tests=1가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 선택 트랙의 W25..현재 selector를 누적 실행하고 첫 트랙 주차인 W25에서 exactly one suite Green과 XML archive를 확인한다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘reference와 learner root는 서로 달라야 한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 tests=1와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

09

STEP 09 / 13

Gradle·JUnit XML·PowerShell·SQL 내부에서 벌어지는 일

세 test phase, XML bytes archive, Review, 별도 Q41, USER_ATTESTED sealed 결과의 owner와 증명 범위를 구분합니다.

source/contract

W25-D6-cumulative.ps1 bytes와 track·phase·hash 계약을 읽는다.

SECURITIES 기본 선택과 파일 존재·phase 이름만으로 runtime Green을 주장할 수 없다. 실제 selected-track evidence와 실행 결과는 별도다.
execution/evidence

RecordRed·RecordGreen·Cumulative에서만 native exit와 exact JUnit XML을 만든다.

미선택 branch와 미래 주차는 누적 claim이 아니다
retention/review

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히토리 → 니지카 → 료 → 키타
  1. 히토리

    status totals=0가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 선택 트랙의 W25..현재 selector를 누적 실행하고 첫 트랙 주차인 W25에서 exactly one suite Green과 XML archive를 확인한다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 status totals=0와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

10

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이 생기지 않는다.

11

STEP 11 / 13

이 코드가 보장하지 않는 것

선택 미결정·10_000 finalState·XML 보존·Review/Q41/sealed official truth처럼 이 코드가 책임지지 않는 일을 분리합니다.

증명 범위

미선택 branch와 미래 주차는 누적 claim이 아니다

이 책임을 맡는 곳: runtime Gate
증명 범위

cumulative log와 XML bytes는 별도 artifact다

이 책임을 맡는 곳: external/human review
증명 범위

reference와 learner root는 서로 달라야 한다

이 책임을 맡는 곳: release manifest
증명 범위

기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다

이 책임을 맡는 곳: 운영 환경
증명하지 않는 범위 — D6 Cumulative — W25 selectorCount=1 누적 Green히토리 → 니지카 → 료 → 키타
  1. 히토리

    cumulative-exact.xml가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 선택 트랙의 W25..현재 selector를 누적 실행하고 첫 트랙 주차인 W25에서 exactly one suite Green과 XML archive를 확인한다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 cumulative-exact.xml와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

12

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. 1. 이 줄은 실행 코드가 아니라 가정·출처·한계를 밝히는 주석이다
  2. 2. W25 첫 트랙 주차의 누적 selector 수가 정확히 1인지 확인한다
  3. 3. PowerShell 오류를 계속 진행하지 않고 중단시키는 기본 정책을 둔다
  4. 4. 입력 경로를 실제 절대 경로로 확인한다
  5. 5. 입력 경로를 실제 절대 경로로 확인한다
  6. 6. 조건·반복·함수의 실행 block을 연다
  7. 7. 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다
  8. 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 책임을 설명할 수 있나?
13

STEP 13 / 13

전체 원본 source

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

학습용 예시 전체 확인하기 · 정본 답안 아님 · NOT_RUN
학습용 예시 · W25 phase wrapper · 정본 답안 아님 · 로컬 미실행illustrative/powershell/W25-D6-cumulative.ps1SHA-256 4be56ad8382d4992e37c6c8b2c11f064193ae465ba9ad85386baea1c90895be6
D6 Cumulative — W25 selectorCount=1 누적 Green 전체
# 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"
18

W25-S1 sealed first pass — 알고리즘 3 + SQL 1

illustrative/powershell/W25-D6-sealed-first-pass.ps1

학습용 예시 · W25 phase wrapper · 정본 답안 아님 · 로컬 미실행 · 학습용 예시 · 정본 답안 아님 · NOT_RUN · W25-F18
105줄 연결105줄 번역9 chunks
01

STEP 01 / 13

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

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

오늘의 한 문장

풀이 전 prompt를 봉인하고 exactly four rows·3 algorithm+1 SQL·shared 150m·10/16/19-field evidence 계약과 user-attested official 경계를 검증한다.

  1. W25-S1은 어느 source와 실제 결과에서 확인해야 할까?
  2. 첫 실패를 만드는 조건과 fail-closed 지점은 어디일까?
  3. 왜 ‘local validator는 official site에 로그인하지 않는다’를 별도 경계로 남겨야 할까?
이 파일에서 끝까지 다시 쓰는 값W25-S13 algorithm + 1 SQLshared ≤150mfirst 16 fieldsretrieval 19 fields
왜 필요한가 — W25-S1 sealed first pass — 알고리즘 3 + SQL 1히토리 → 니지카 → 료 → 키타
  1. 히토리

    W25-S1가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 풀이 전 prompt를 봉인하고 exactly four rows·3 algorithm+1 SQL·shared 150m·10/16/19-field evidence 계약과 user-attested official 경계를 검증한다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘local validator는 official site에 로그인하지 않는다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 W25-S1와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

02

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 확인을 대신하지 않는다.

03

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이며 실제 실행은 정확히 한 트랙에만 귀속한다
04

STEP 04 / 13

비유 ↔ 코드 전체 연결표

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

단어 몇 개만 뽑은 표가 아닙니다.학습용 예시 · W25 phase wrapper · 정본 답안 아님 · 로컬 미실행에서 비어 있지 않은 모든 줄을 원본 줄 번호 그대로 연결했습니다.105 / 105 연결
정확한 원본 줄STARRY 비유실제 뜻·입력·결과·한계
1줄F18-L01 $ErrorActionPreference='Stop' 출고표 1번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 PowerShell 오류를 계속 진행하지 않고 중단시키는 기본 정책을 둔다.
입력
$ErrorActionPreference, 'Stop'
결과·효과
관찰 상태 F18-001가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
local validator는 official site에 로그인하지 않는다
2줄F18-L02 function Read-ExactSealedKv([string]$Path,[string]$Label,[string[]]$Required){ 출고표 2번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 조건·반복·함수의 실행 block을 연다.
입력
$Path, $Label, $Required
결과·효과
관찰 상태 F18-002가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
ACCEPTED/REJECTED는 USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED다
3줄F18-L03 if(!(Test-Path -LiteralPath $Path -PathType Leaf) -or (Get-Item -LiteralPath $Path).Length -eq 0){throw "missing/empty ${Label}: $Path"} 출고표 3번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 필수 파일이나 경로가 실제로 있는지 확인한다.
입력
$Path, $Path, 0
결과·효과
관찰 상태 F18-003가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
evaluator independence를 완전 증명하지 않는다
4줄F18-L04 $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"} 출고표 4번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
입력
$raw, $Path, $raw
결과·효과
관찰 상태 F18-004가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
5줄F18-L05 $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} 출고표 5번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
입력
$map, $line, $Path
결과·효과
관찰 상태 F18-005가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
6줄F18-L06 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"}} 출고표 6번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
입력
$map, $Required, $Label
결과·효과
관찰 상태 F18-006가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
7줄F18-L07 return $map 출고표 7번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 W25-D6-sealed-first-pass.ps1의 다음 검증 또는 설명 단계를 구성한다.
입력
$map
결과·효과
관찰 상태 F18-007가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
local validator는 official site에 로그인하지 않는다
8줄F18-L08 } 출고표 8번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
입력
이전 줄의 상태와 W25-S1
결과·효과
관찰 상태 F18-008가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
ACCEPTED/REJECTED는 USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED다
9줄F18-L09 function Assert-SealedPromptContract([object]$Row){ 출고표 9번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 조건·반복·함수의 실행 block을 연다.
입력
$Row
결과·효과
관찰 상태 F18-009가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
evaluator independence를 완전 증명하지 않는다
10줄F18-L10 $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 출고표 10번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
입력
$required, 'PROBLEM_ID', 'SOURCE_URL'
결과·효과
관찰 상태 F18-010가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
11줄F18-L11 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)"} 출고표 11번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
입력
$prompt, $Row, $Row
결과·효과
관찰 상태 F18-011가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
12줄F18-L12 if($prompt.PROMPT_ONLY -cne 'true' -or $prompt.SOLUTION_INCLUDED -cne 'false'){throw "prompt-only flags invalid problem=$($Row.problem_id)"} 출고표 12번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
입력
$prompt, 'true', $prompt
결과·효과
관찰 상태 F18-012가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
13줄F18-L13 $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)"} 출고표 13번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 현재 bytes를 64자리 digest로 evidence에 결박한다.
입력
$actual, $Row, $Row
결과·효과
관찰 상태 F18-013가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
local validator는 official site에 로그인하지 않는다
14줄F18-L14 } 출고표 14번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
입력
이전 줄의 상태와 W25-S1
결과·효과
관찰 상태 F18-014가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
ACCEPTED/REJECTED는 USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED다
15줄F18-L15 function Assert-SealedFirstEvidence([object]$Row){ 출고표 15번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 조건·반복·함수의 실행 block을 연다.
입력
$Row
결과·효과
관찰 상태 F18-015가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
evaluator independence를 완전 증명하지 않는다
16줄F18-L16 $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 출고표 16번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 현재 bytes를 64자리 digest로 evidence에 결박한다.
입력
$required, 'PROBLEM_ID', 'ATTEMPT'
결과·효과
관찰 상태 F18-016가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
17줄F18-L17 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)"} 출고표 17번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
입력
$manifest, $Row, $manifest
결과·효과
관찰 상태 F18-017가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
18줄F18-L18 $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)"} 출고표 18번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 각 demo 단계가 반드시 반환해야 할 HTTP status를 입력으로 고정한다.
입력
$expectedStatus, $Row, 'PASS'
결과·효과
관찰 상태 F18-018가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
19줄F18-L19 $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)"} 출고표 19번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
입력
$officialUri, $null, $manifest
결과·효과
관찰 상태 F18-019가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
local validator는 official site에 로그인하지 않는다
20줄F18-L20 $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)"}} 출고표 20번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 현재 bytes를 64자리 digest로 evidence에 결박한다.
입력
$nativeTranscript, $manifest, $solution
결과·효과
관찰 상태 F18-020가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
ACCEPTED/REJECTED는 USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED다
21줄F18-L21 $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)"} 출고표 21번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
입력
$paths, $Row, $Row
결과·효과
관찰 상태 F18-021가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
evaluator independence를 완전 증명하지 않는다
22줄F18-L22 $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"}} 출고표 22번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
입력
$nativeBody, $nativeTranscript, $token
결과·효과
관찰 상태 F18-022가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
23줄F18-L23 $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"}} 출고표 23번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 각 demo 단계가 반드시 반환해야 할 HTTP status를 입력으로 고정한다.
입력
$officialBody, $officialSnapshot, $token
결과·효과
관찰 상태 F18-023가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
24줄F18-L24 } 출고표 24번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
입력
이전 줄의 상태와 W25-S1
결과·효과
관찰 상태 F18-024가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
25줄F18-L25 function Assert-SealedRetrievalEvidence([object]$Row){ 출고표 25번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 조건·반복·함수의 실행 block을 연다.
입력
$Row
결과·효과
관찰 상태 F18-025가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
local validator는 official site에 로그인하지 않는다
26줄F18-L26 $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 출고표 26번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 현재 bytes를 64자리 digest로 evidence에 결박한다.
입력
$required, 'PROBLEM_ID', 'ATTEMPT'
결과·효과
관찰 상태 F18-026가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
ACCEPTED/REJECTED는 USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED다
27줄F18-L27 if($manifest.PROBLEM_ID -cne $Row.problem_id -or $manifest.ATTEMPT -cne 'RETRIEVAL'){throw "retrieval identity mismatch problem=$($Row.problem_id)"} 출고표 27번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
입력
$manifest, $Row, $manifest
결과·효과
관찰 상태 F18-027가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
evaluator independence를 완전 증명하지 않는다
28줄F18-L28 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)"} 출고표 28번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 현재 bytes를 64자리 digest로 evidence에 결박한다.
입력
$manifest, $Row, $Row
결과·효과
관찰 상태 F18-028가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
29줄F18-L29 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)"} 출고표 29번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
입력
$manifest, '0', $manifest
결과·효과
관찰 상태 F18-029가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
30줄F18-L30 $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)"} 출고표 30번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 각 demo 단계가 반드시 반환해야 할 HTTP status를 입력으로 고정한다.
입력
$expectedStatus, $Row, 'PASS'
결과·효과
관찰 상태 F18-030가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
31줄F18-L31 $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)"} 출고표 31번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
입력
$officialUri, $null, $manifest
결과·효과
관찰 상태 F18-031가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
local validator는 official site에 로그인하지 않는다
32줄F18-L32 $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)"}} 출고표 32번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 현재 bytes를 64자리 digest로 evidence에 결박한다.
입력
$nativeTranscript, $manifest, $solution
결과·효과
관찰 상태 F18-032가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
ACCEPTED/REJECTED는 USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED다
33줄F18-L33 $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)"} 출고표 33번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
입력
$paths, $Row, $Row
결과·효과
관찰 상태 F18-033가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
evaluator independence를 완전 증명하지 않는다
34줄F18-L34 $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"}} 출고표 34번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
입력
$nativeBody, $nativeTranscript, $token
결과·효과
관찰 상태 F18-034가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
35줄F18-L35 $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)"} 출고표 35번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 각 demo 단계가 반드시 반환해야 할 HTTP status를 입력으로 고정한다.
입력
$submissionBody, $submission, $token
결과·효과
관찰 상태 F18-035가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
36줄F18-L36 $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)"} 출고표 36번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 현재 bytes를 64자리 digest로 evidence에 결박한다.
입력
$actualManifest, $Row, $Row
결과·효과
관찰 상태 F18-036가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
37줄F18-L37 } 출고표 37번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
입력
이전 줄의 상태와 W25-S1
결과·효과
관찰 상태 F18-037가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
local validator는 official site에 로그인하지 않는다
38줄F18-L38 $p='evidence/w25/sealed-first-pass.csv' 출고표 38번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
입력
$p, 'evidence/w25/sealed-first-pass.csv'
결과·효과
관찰 상태 F18-038가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
ACCEPTED/REJECTED는 USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED다
39줄F18-L39 $exposurePath='evidence/w25/pre-attempt-exposure.csv' 출고표 39번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
입력
$exposurePath, 'evidence/w25/pre-attempt-exposure.csv'
결과·효과
관찰 상태 F18-039가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
evaluator independence를 완전 증명하지 않는다
40줄F18-L40 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"}} 출고표 40번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 필수 파일이나 경로가 실제로 있는지 확인한다.
입력
$file, $p, $exposurePath
결과·효과
관찰 상태 F18-040가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
41줄F18-L41 $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' 출고표 41번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 현재 bytes를 64자리 digest로 evidence에 결박한다.
입력
$header
결과·효과
관찰 상태 F18-041가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
42줄F18-L42 if((Get-Content -LiteralPath $p -TotalCount 1) -cne $header){throw 'sealed registry exact header mismatch'} 출고표 42번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
입력
$p, 1, $header
결과·효과
관찰 상태 F18-042가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
43줄F18-L43 $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'} 출고표 43번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
입력
$exposureHeader, $exposurePath, 1
결과·효과
관찰 상태 F18-043가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
local validator는 official site에 로그인하지 않는다
44줄F18-L44 $expectedHistoryWeeks=@() 출고표 44번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
입력
$expectedHistoryWeeks
결과·효과
관찰 상태 F18-044가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
ACCEPTED/REJECTED는 USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED다
45줄F18-L45 $historyRows=@() 출고표 45번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
입력
$historyRows
결과·효과
관찰 상태 F18-045가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
evaluator independence를 완전 증명하지 않는다
46줄F18-L46 foreach($priorWeek in $expectedHistoryWeeks){ 출고표 46번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 고정 목록의 각 항목에 같은 검사를 반복 적용한다.
입력
$priorWeek, $expectedHistoryWeeks
결과·효과
관찰 상태 F18-046가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
47줄F18-L47 $historyPath=('evidence/w{0:D2}/sealed-first-pass.csv' -f [int]$priorWeek) 출고표 47번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
입력
$historyPath, 'evidence/w{0:D2}/sealed-first-pass.csv', $priorWeek
결과·효과
관찰 상태 F18-047가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
48줄F18-L48 if(!(Test-Path -LiteralPath $historyPath -PathType Leaf)){throw "missing immutable sealed history week=W$priorWeek path=$historyPath"} 출고표 48번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 필수 파일이나 경로가 실제로 있는지 확인한다.
입력
$historyPath, $priorWeek, $historyPath
결과·효과
관찰 상태 F18-048가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
49줄F18-L49 $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'} 출고표 49번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 현재 bytes를 64자리 digest로 evidence에 결박한다.
입력
$expectedHistoryHeader, $priorWeek, 47
결과·효과
관찰 상태 F18-049가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
local validator는 official site에 로그인하지 않는다
50줄F18-L50 if((Get-Content -LiteralPath $historyPath -TotalCount 1) -cne $expectedHistoryHeader){throw "sealed history header mismatch week=W$priorWeek"} 출고표 50번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
입력
$historyPath, 1, $expectedHistoryHeader
결과·효과
관찰 상태 F18-050가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
ACCEPTED/REJECTED는 USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED다
51줄F18-L51 $priorRows=@(Import-Csv -LiteralPath $historyPath);$expectedPriorCount=if([int]$priorWeek -ge 47){10}else{4} 출고표 51번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
입력
$priorRows, $historyPath, $expectedPriorCount
결과·효과
관찰 상태 F18-051가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
evaluator independence를 완전 증명하지 않는다
52줄F18-L52 if($priorRows.Count -ne $expectedPriorCount){throw "sealed history row count mismatch week=W$priorWeek expected=$expectedPriorCount actual=$($priorRows.Count)"} 출고표 52번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
입력
$priorRows, $expectedPriorCount, $priorWeek
결과·효과
관찰 상태 F18-052가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
53줄F18-L53 if($priorRows|Group-Object problem_id|Where-Object Count -ne 1){throw "duplicate problem ID inside sealed history week=W$priorWeek"} 출고표 53번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
입력
$priorRows, 1, $priorWeek
결과·효과
관찰 상태 F18-053가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
54줄F18-L54 foreach($priorRow in $priorRows){ 출고표 54번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 고정 목록의 각 항목에 같은 검사를 반복 적용한다.
입력
$priorRow, $priorRows
결과·효과
관찰 상태 F18-054가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
55줄F18-L55 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"}} 출고표 55번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 현재 bytes를 64자리 digest로 evidence에 결박한다.
입력
$field, 'problem_id', 'source_url'
결과·효과
관찰 상태 F18-055가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
local validator는 official site에 로그인하지 않는다
56줄F18-L56 $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)"} 출고표 56번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
입력
$historyUri, $null, $priorRow
결과·효과
관찰 상태 F18-056가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
ACCEPTED/REJECTED는 USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED다
57줄F18-L57 if($priorRow.exposure_class -cne 'sealed_first_pass'){throw "ineligible sealed history exposure class week=W$priorWeek problem=$($priorRow.problem_id)"} 출고표 57번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
입력
$priorRow, 'sealed_first_pass', $priorWeek
결과·효과
관찰 상태 F18-057가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
evaluator independence를 완전 증명하지 않는다
58줄F18-L58 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)"}} 출고표 58번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 현재 bytes를 64자리 digest로 evidence에 결박한다.
입력
$pair, $priorRow, $priorRow
결과·효과
관찰 상태 F18-058가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
59줄F18-L59 $null=Assert-SealedPromptContract $priorRow;$null=Assert-SealedFirstEvidence $priorRow 출고표 59번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
입력
$null, $priorRow, $null
결과·효과
관찰 상태 F18-059가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
60줄F18-L60 } 출고표 60번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
입력
이전 줄의 상태와 W25-S1
결과·효과
관찰 상태 F18-060가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
61줄F18-L61 $historyRows+=@($priorRows) 출고표 61번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
입력
$historyRows, $priorRows
결과·효과
관찰 상태 F18-061가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
local validator는 official site에 로그인하지 않는다
62줄F18-L62 } 출고표 62번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
입력
이전 줄의 상태와 W25-S1
결과·효과
관찰 상태 F18-062가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
ACCEPTED/REJECTED는 USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED다
63줄F18-L63 if($historyRows|Group-Object problem_id|Where-Object Count -ne 1){throw 'problem ID reused across prior sealed weeks'} 출고표 63번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
입력
$historyRows, 1
결과·효과
관찰 상태 F18-063가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
evaluator independence를 완전 증명하지 않는다
64줄F18-L64 $historyIds=@($historyRows|ForEach-Object {$_.problem_id}) 출고표 64번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 고정 목록의 각 항목에 같은 검사를 반복 적용한다.
입력
$historyIds, $historyRows, $_
결과·효과
관찰 상태 F18-064가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
65줄F18-L65 $allRows=@(Import-Csv -LiteralPath $p) 출고표 65번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
입력
$allRows, $p
결과·효과
관찰 상태 F18-065가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
66줄F18-L66 $canonicalCurrentMocks=@('W25-S1') 출고표 66번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 같은 시작 시각으로 봉인한 알고리즘 3문제와 SQL 1문제의 first pass를 가리키며 official status는 사용자 attestation 범위다.
입력
$canonicalCurrentMocks, 'W25-S1'
결과·효과
관찰 상태 F18-066가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
67줄F18-L67 if($allRows|Where-Object {$canonicalCurrentMocks -cnotcontains $_.mock_id}){throw 'sealed current file contains unknown mock'} 출고표 67번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
입력
$allRows, $canonicalCurrentMocks, $_
결과·효과
관찰 상태 F18-067가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
local validator는 official site에 로그인하지 않는다
68줄F18-L68 if($allRows|Group-Object problem_id|Where-Object Count -ne 1){throw 'duplicate problem ID across current sealed mocks'} 출고표 68번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
입력
$allRows, 1
결과·효과
관찰 상태 F18-068가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
ACCEPTED/REJECTED는 USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED다
69줄F18-L69 foreach($currentGroup in @($allRows|Group-Object mock_id)){if($currentGroup.Count -ne 4){throw "partial current mock=$($currentGroup.Name) rows=$($currentGroup.Count) expected=4"}} 출고표 69번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
입력
$currentGroup, $allRows, $currentGroup
결과·효과
관찰 상태 F18-069가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
evaluator independence를 완전 증명하지 않는다
70줄F18-L70 $rows=@($allRows|Where-Object {$_.mock_id -cin @('W25-S1')}) 출고표 70번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 같은 시작 시각으로 봉인한 알고리즘 3문제와 SQL 1문제의 first pass를 가리키며 official status는 사용자 attestation 범위다.
입력
$rows, $allRows, $_
결과·효과
관찰 상태 F18-070가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
71줄F18-L71 $exposures=@(Import-Csv -LiteralPath $exposurePath) 출고표 71번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
입력
$exposures, $exposurePath
결과·효과
관찰 상태 F18-071가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
72줄F18-L72 if($rows.Count -ne 4){throw "sealed registry requires exactly 4 rows; actual=$($rows.Count)"} 출고표 72번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
입력
$rows, 4, 4
결과·효과
관찰 상태 F18-072가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
73줄F18-L73 if($rows|Group-Object problem_id|Where-Object Count -ne 1){throw 'duplicate/pre-exposed problem ID collision'} 출고표 73번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
입력
$rows, 1
결과·효과
관찰 상태 F18-073가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
local validator는 official site에 로그인하지 않는다
74줄F18-L74 if($exposures|Group-Object problem_id|Where-Object Count -ne 1){throw 'duplicate pre-attempt exposure problem_id'} 출고표 74번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
입력
$exposures, 1
결과·효과
관찰 상태 F18-074가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
ACCEPTED/REJECTED는 USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED다
75줄F18-L75 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)"}} 출고표 75번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 필수 파일이나 경로가 실제로 있는지 확인한다.
입력
$x, $exposures, $field
결과·효과
관찰 상태 F18-075가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
evaluator independence를 완전 증명하지 않는다
76줄F18-L76 $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') 출고표 76번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
입력
$denied, 'FCL-SQL-41', 'FCL-SQL-42'
결과·효과
관찰 상태 F18-076가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
77줄F18-L77 $expectedMocks=@('W25-S1') 출고표 77번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 같은 시작 시각으로 봉인한 알고리즘 3문제와 SQL 1문제의 first pass를 가리키며 official status는 사용자 attestation 범위다.
입력
$expectedMocks, 'W25-S1'
결과·효과
관찰 상태 F18-077가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
78줄F18-L78 $requireRetrieval=$false;$pending=0 출고표 78번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
입력
$requireRetrieval, $false, $pending
결과·효과
관찰 상태 F18-078가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
79줄F18-L79 foreach($row in $rows){ 출고표 79번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 고정 목록의 각 항목에 같은 검사를 반복 적용한다.
입력
$row, $rows
결과·효과
관찰 상태 F18-079가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
local validator는 official site에 로그인하지 않는다
80줄F18-L80 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)"}} 출고표 80번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 현재 bytes를 64자리 digest로 evidence에 결박한다.
입력
$field, 'mock_id', 'problem_id'
결과·효과
관찰 상태 F18-080가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
ACCEPTED/REJECTED는 USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED다
81줄F18-L81 if($expectedMocks -cnotcontains $row.mock_id){throw "unknown mock: $($row.mock_id)"} 출고표 81번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
입력
$expectedMocks, $row, "unknown mock: $($row.mock_id)"
결과·효과
관찰 상태 F18-081가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
evaluator independence를 완전 증명하지 않는다
82줄F18-L82 if($denied -ccontains $row.problem_id){throw "known guided/pre-exposed problem ID collision: $($row.problem_id)"} 출고표 82번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
입력
$denied, $row, $row
결과·효과
관찰 상태 F18-082가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
83줄F18-L83 if($historyIds -ccontains $row.problem_id){throw "prior sealed problem ID collision: $($row.problem_id)"} 출고표 83번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
입력
$historyIds, $row, $row
결과·효과
관찰 상태 F18-083가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
84줄F18-L84 if(@($exposures|Where-Object {$_.problem_id -ceq $row.problem_id}).Count){throw "pre-attempt exposure collision: $($row.problem_id)"} 출고표 84번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
입력
$exposures, $_, $row
결과·효과
관찰 상태 F18-084가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
85줄F18-L85 if(@('algorithm','SQL') -cnotcontains $row.kind){throw "kind must be algorithm|SQL: $($row.problem_id)"} 출고표 85번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
입력
'algorithm', 'SQL', $row
결과·효과
관찰 상태 F18-085가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
local validator는 official site에 로그인하지 않는다
86줄F18-L86 $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"} 출고표 86번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
입력
$uri, $null, $row
결과·효과
관찰 상태 F18-086가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
ACCEPTED/REJECTED는 USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED다
87줄F18-L87 if($row.exposure_class -cne 'sealed_first_pass'){throw "pre-exposed/ineligible item: $($row.problem_id)"} 출고표 87번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
입력
$row, 'sealed_first_pass', $row
결과·효과
관찰 상태 F18-087가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
evaluator independence를 완전 증명하지 않는다
88줄F18-L88 if($row.hint_level -cne 'NONE'){throw "hinted item is not first-pass eligible: $($row.problem_id)"} 출고표 88번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
입력
$row, 'NONE', $row
결과·효과
관찰 상태 F18-088가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
89줄F18-L89 if($row.native_exit -cne '0' -or @('PASS','FAIL') -cnotcontains $row.first_result){throw "native exit/result invalid: $($row.problem_id)"} 출고표 89번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
입력
$row, '0', 'PASS'
결과·효과
관찰 상태 F18-089가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
90줄F18-L90 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)"}} 출고표 90번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
입력
$timeField, 'source_checked_at', 'revealed_at'
결과·효과
관찰 상태 F18-090가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
91줄F18-L91 $checked=[datetimeoffset]::MinValue;$reveal=[datetimeoffset]::MinValue;$start=[datetimeoffset]::MinValue;$submit=[datetimeoffset]::MinValue 출고표 91번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
입력
$checked, $reveal, $start
결과·효과
관찰 상태 F18-091가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
local validator는 official site에 로그인하지 않는다
92줄F18-L92 if(![datetimeoffset]::TryParse($row.source_checked_at,[ref]$checked)){throw "invalid source_checked_at: $($row.problem_id)"} 출고표 92번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
입력
$row, $checked, $row
결과·효과
관찰 상태 F18-092가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
ACCEPTED/REJECTED는 USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED다
93줄F18-L93 if(![datetimeoffset]::TryParse($row.revealed_at,[Globalization.CultureInfo]::InvariantCulture,[Globalization.DateTimeStyles]::RoundtripKind,[ref]$reveal)){throw "invalid revealed_at: $($row.problem_id)"} 출고표 93번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
입력
$row, $reveal, "invalid revealed_at: $($row.problem_id)"
결과·효과
관찰 상태 F18-093가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
evaluator independence를 완전 증명하지 않는다
94줄F18-L94 if(![datetimeoffset]::TryParse($row.started_at,[Globalization.CultureInfo]::InvariantCulture,[Globalization.DateTimeStyles]::RoundtripKind,[ref]$start)){throw "invalid started_at: $($row.problem_id)"} 출고표 94번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
입력
$row, $start, "invalid started_at: $($row.problem_id)"
결과·효과
관찰 상태 F18-094가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
95줄F18-L95 if(![datetimeoffset]::TryParse($row.submitted_at,[Globalization.CultureInfo]::InvariantCulture,[Globalization.DateTimeStyles]::RoundtripKind,[ref]$submit)){throw "invalid submitted_at: $($row.problem_id)"} 출고표 95번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
입력
$row, $submit, "invalid submitted_at: $($row.problem_id)"
결과·효과
관찰 상태 F18-095가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
96줄F18-L96 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)"} 출고표 96번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
입력
$checked, $reveal, $reveal
결과·효과
관찰 상태 F18-096가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
97줄F18-L97 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)"}} 출고표 97번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 현재 bytes를 64자리 digest로 evidence에 결박한다.
입력
$pair, $row, $row
결과·효과
관찰 상태 F18-097가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
local validator는 official site에 로그인하지 않는다
98줄F18-L98 $null=Assert-SealedPromptContract $row;$null=Assert-SealedFirstEvidence $row 출고표 98번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
입력
$null, $row, $null
결과·효과
관찰 상태 F18-098가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
ACCEPTED/REJECTED는 USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED다
99줄F18-L99 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{ 출고표 99번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 현재 bytes를 64자리 digest로 evidence에 결박한다.
입력
$row, 'PASS', $row
결과·효과
관찰 상태 F18-099가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
evaluator independence를 완전 증명하지 않는다
100줄F18-L100 $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} 출고표 100번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 현재 bytes를 64자리 digest로 evidence에 결박한다.
입력
$retrievalTuple, $row, $row
결과·효과
관찰 상태 F18-100가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
101줄F18-L101 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 출고표 101번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 현재 bytes를 64자리 digest로 evidence에 결박한다.
입력
$retrievalTuple, $_, 'N-A_FAST_TRACK'
결과·효과
관찰 상태 F18-101가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
102줄F18-L102 } 출고표 102번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
입력
이전 줄의 상태와 W25-S1
결과·효과
관찰 상태 F18-102가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
103줄F18-L103 } 출고표 103번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
입력
이전 줄의 상태와 W25-S1
결과·효과
관찰 상태 F18-103가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
local validator는 official site에 로그인하지 않는다
104줄F18-L104 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"}} 출고표 104번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
입력
$mock, $expectedMocks, $m
결과·효과
관찰 상태 F18-104가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
ACCEPTED/REJECTED는 USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED다
105줄F18-L105 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'} 출고표 105번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 W25-D6-sealed-first-pass.ps1의 다음 검증 또는 설명 단계를 구성한다.
입력
$pending, 0, 1
결과·효과
관찰 상태 F18-105가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
evaluator independence를 완전 증명하지 않는다
05

STEP 05 / 13

원본 코드 조각

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

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

F18-C01 · 원문 1–12줄1–12줄
1–12줄 원본
$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)"}
F18-C02 · 원문 13–24줄13–24줄
13–24줄 원본
  $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"}}
}
F18-C03 · 원문 25–36줄25–36줄
25–36줄 원본
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)"}
F18-C04 · 원문 37–48줄37–48줄
37–48줄 원본
}
$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"}
F18-C05 · 원문 49–60줄49–60줄
49–60줄 원본
  $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
  }
F18-C06 · 원문 61–72줄61–72줄
61–72줄 원본
  $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)"}
F18-C07 · 원문 73–84줄73–84줄
73–84줄 원본
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)"}
F18-C08 · 원문 85–96줄85–96줄
85–96줄 원본
  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)"}
F18-C09 · 원문 97–105줄97–105줄
97–105줄 원본
  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'}
06

STEP 06 / 13

코드 한 줄씩 한국어로 번역

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

전체 번역 105 / 105

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

원본한국어 번역
1$ErrorActionPreference='Stop'실행 의미: PowerShell 오류를 계속 진행하지 않고 중단시키는 기본 정책을 둔다.
2function 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 또는 호출 범위를 닫는다.
9function 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 또는 호출 범위를 닫는다.
15function 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 또는 호출 범위를 닫는다.
25function 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 변수에 저장한다.
40foreach($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에 결박한다.
42if((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 변수에 저장한다.
46foreach($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 또는 호출 범위를 닫는다.
63if($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 범위다.
67if($allRows|Where-Object {$canonicalCurrentMocks -cnotcontains $_.mock_id}){throw 'sealed current file contains unknown mock'}실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
68if($allRows|Group-Object problem_id|Where-Object Count -ne 1){throw 'duplicate problem ID across current sealed mocks'}실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
69foreach($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 변수에 저장한다.
72if($rows.Count -ne 4){throw "sealed registry requires exactly 4 rows; actual=$($rows.Count)"}실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
73if($rows|Group-Object problem_id|Where-Object Count -ne 1){throw 'duplicate/pre-exposed problem ID collision'}실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
74if($exposures|Group-Object problem_id|Where-Object Count -ne 1){throw 'duplicate pre-attempt exposure problem_id'}실행 의미: 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
75foreach($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 변수에 저장한다.
79foreach($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 또는 호출 범위를 닫는다.
104foreach($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 전에 실행을 중단한다.
105if($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의 다음 검증 또는 설명 단계를 구성한다.
07

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를 서로 대체하지 않는다.

실행 순서

  1. 기본 트랙은 SECURITIES(증권)이며, 명시적 CARD 선택은 기본값을 덮어쓴다. 실제 실행 전 최종 선택 한 개를 selected-track.csv·근거·state에 같은 값으로 기록하고 서로 다른 reference/learner root를 확인한다.
  2. Prepare→VerifyStarter→RecordRed→VerifySolution→RecordGreen→Cumulative→Review 순서를 지킨다.
  3. test를 소유한 세 phase에서만 native exit와 exact JUnit XML 수치를 판정한다.
  4. 다음 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히토리 → 니지카 → 료 → 키타
  1. 히토리

    3 algorithm + 1 SQL가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 풀이 전 prompt를 봉인하고 exactly four rows·3 algorithm+1 SQL·shared 150m·10/16/19-field evidence 계약과 user-attested official 경계를 검증한다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘ACCEPTED/REJECTED는 USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 3 algorithm + 1 SQL와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

08

STEP 08 / 13

실제 값 따라가기

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

순서들어온 값코드가 하는 일나온 값·상태경계
입력W25-S1source 계약에 대입F18 실행/설명 시작 상태local validator는 official site에 로그인하지 않는다
검증3 algorithm + 1 SQLexpected와 actual 또는 형식 대조통과 또는 첫 mismatchACCEPTED/REJECTED는 USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED다
증거retrieval 19 fieldsmarker·hash·row를 같은 run에 연결범위가 적힌 evidence 후보이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
실제 값 — W25-S1 sealed first pass — 알고리즘 3 + SQL 1히토리 → 니지카 → 료 → 키타
  1. 히토리

    shared ≤150m가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 풀이 전 prompt를 봉인하고 exactly four rows·3 algorithm+1 SQL·shared 150m·10/16/19-field evidence 계약과 user-attested official 경계를 검증한다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘evaluator independence를 완전 증명하지 않는다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 shared ≤150m와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

09

STEP 09 / 13

Gradle·JUnit XML·PowerShell·SQL 내부에서 벌어지는 일

세 test phase, XML bytes archive, Review, 별도 Q41, USER_ATTESTED sealed 결과의 owner와 증명 범위를 구분합니다.

source/contract

W25-D6-sealed-first-pass.ps1 bytes와 track·phase·hash 계약을 읽는다.

SECURITIES 기본 선택과 파일 존재·phase 이름만으로 runtime Green을 주장할 수 없다. 실제 selected-track evidence와 실행 결과는 별도다.
execution/evidence

RecordRed·RecordGreen·Cumulative에서만 native exit와 exact JUnit XML을 만든다.

local validator는 official site에 로그인하지 않는다
retention/review

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히토리 → 니지카 → 료 → 키타
  1. 히토리

    first 16 fields가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 풀이 전 prompt를 봉인하고 exactly four rows·3 algorithm+1 SQL·shared 150m·10/16/19-field evidence 계약과 user-attested official 경계를 검증한다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘reference와 learner root는 서로 달라야 한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 first 16 fields와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

10

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이 생기지 않는다.

11

STEP 11 / 13

이 코드가 보장하지 않는 것

선택 미결정·10_000 finalState·XML 보존·Review/Q41/sealed official truth처럼 이 코드가 책임지지 않는 일을 분리합니다.

증명 범위

local validator는 official site에 로그인하지 않는다

이 책임을 맡는 곳: runtime Gate
증명 범위

ACCEPTED/REJECTED는 USER_ATTESTED_NOT_AUTOMATICALLY_VERIFIED다

이 책임을 맡는 곳: external/human review
증명 범위

evaluator independence를 완전 증명하지 않는다

이 책임을 맡는 곳: release manifest
증명 범위

reference와 learner root는 서로 달라야 한다

이 책임을 맡는 곳: 운영 환경
증명하지 않는 범위 — W25-S1 sealed first pass — 알고리즘 3 + SQL 1히토리 → 니지카 → 료 → 키타
  1. 히토리

    retrieval 19 fields가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 풀이 전 prompt를 봉인하고 exactly four rows·3 algorithm+1 SQL·shared 150m·10/16/19-field evidence 계약과 user-attested official 경계를 검증한다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 retrieval 19 fields와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

12

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. 1. PowerShell 오류를 계속 진행하지 않고 중단시키는 기본 정책을 둔다
  2. 2. 조건·반복·함수의 실행 block을 연다
  3. 3. 필수 파일이나 경로가 실제로 있는지 확인한다
  4. 4. 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다
  5. 5. 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다
  6. 6. 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다
  7. 7. W25-D6-sealed-first-pass.ps1의 다음 검증 또는 설명 단계를 구성한다
  8. 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 책임을 설명할 수 있나?
13

STEP 13 / 13

전체 원본 source

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

학습용 예시 전체 확인하기 · 정본 답안 아님 · NOT_RUN
학습용 예시 · W25 phase wrapper · 정본 답안 아님 · 로컬 미실행illustrative/powershell/W25-D6-sealed-first-pass.ps1SHA-256 96570b67fb75557036bf70d1f5d6570dba5554fcd1d1c18c0f3f580da3b3cbd5
W25-S1 sealed first pass — 알고리즘 3 + SQL 1 전체
$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'}
19

D7 Review — 기존 CumulativeGreen을 reviewedPhase로 연결

illustrative/powershell/W25-D7-review.ps1

학습용 예시 · W25 phase wrapper · 정본 답안 아님 · 로컬 미실행 · 학습용 예시 · 정본 답안 아님 · NOT_RUN · W25-F19
23줄 연결23줄 번역3 chunks
01

STEP 01 / 13

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

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

오늘의 한 문장

새 Gradle/XML을 만들지 않고 prior CumulativeGreen·leak 경계·history 증가를 확인하며 phase는 CumulativeGreen으로 유지한다.

  1. Review requires CumulativeGreen은 어느 source와 실제 결과에서 확인해야 할까?
  2. 첫 실패를 만드는 조건과 fail-closed 지점은 어디일까?
  3. 왜 ‘Review는 Git commit·audio·설명 의미를 자동 검증하지 않는다’를 별도 경계로 남겨야 할까?
이 파일에서 끝까지 다시 쓰는 값Review requires CumulativeGreenreviewedPhase=CumulativeGreenphase remains CumulativeGreenno new executionruntime_claim=false
왜 필요한가 — D7 Review — 기존 CumulativeGreen을 reviewedPhase로 연결히토리 → 니지카 → 료 → 키타
  1. 히토리

    Review requires CumulativeGreen가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 새 Gradle/XML을 만들지 않고 prior CumulativeGreen·leak 경계·history 증가를 확인하며 phase는 CumulativeGreen으로 유지한다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘Review는 Git commit·audio·설명 의미를 자동 검증하지 않는다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 Review requires CumulativeGreen와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

02

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 확인을 대신하지 않는다.

03

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을 실행하지 않았다
04

STEP 04 / 13

비유 ↔ 코드 전체 연결표

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

단어 몇 개만 뽑은 표가 아닙니다.학습용 예시 · W25 phase wrapper · 정본 답안 아님 · 로컬 미실행에서 비어 있지 않은 모든 줄을 원본 줄 번호 그대로 연결했습니다.23 / 23 연결
정확한 원본 줄STARRY 비유실제 뜻·입력·결과·한계
1줄F19-L01 # W25 PDF p48-p52의 Review 흐름을 정리한 학습용 예시다. 출고표 1번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 기존 CumulativeGreen을 전제로 review entry와 leak 경계만 다시 기록한다.
입력
이전 줄의 상태와 Review requires CumulativeGreen
결과·효과
관찰 상태 F19-001가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
Review는 Git commit·audio·설명 의미를 자동 검증하지 않는다
2줄F19-L02 # Review는 새 Gradle/XML을 읽지 않고 기존 CumulativeGreen history와 leak 경계를 다시 확인한다. 출고표 2번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 W25부터 현재 주까지 선택 트랙 selector를 누적 실행하는 phase다.
입력
이전 줄의 상태와 Review requires CumulativeGreen
결과·효과
관찰 상태 F19-002가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
hash는 XML bytes·사람 설명을 대신하지 않는다
3줄F19-L03 $ErrorActionPreference = 'Stop' 출고표 3번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 PowerShell 오류를 계속 진행하지 않고 중단시키는 기본 정책을 둔다.
입력
$ErrorActionPreference, 'Stop'
결과·효과
관찰 상태 F19-003가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
4줄F19-L04 $ReferenceRoot = (Resolve-Path -LiteralPath $env:FINANCIAL_IT_REFERENCE_ROOT).Path 출고표 4번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 입력 경로를 실제 절대 경로로 확인한다.
입력
$ReferenceRoot, $env
결과·효과
관찰 상태 F19-004가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
5줄F19-L05 $LearnerRoot = (Resolve-Path -LiteralPath $env:FINANCIAL_IT_LEARNER_ROOT).Path 출고표 5번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 입력 경로를 실제 절대 경로로 확인한다.
입력
$LearnerRoot, $env
결과·효과
관찰 상태 F19-005가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
6줄F19-L06 if ([string]::Equals($ReferenceRoot, $LearnerRoot, [StringComparison]::OrdinalIgnoreCase)) { 출고표 6번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 조건·반복·함수의 실행 block을 연다.
입력
$ReferenceRoot, $LearnerRoot
결과·효과
관찰 상태 F19-006가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
Review는 Git commit·audio·설명 의미를 자동 검증하지 않는다
7줄F19-L07 throw 'reference and learner roots must be different' 출고표 7번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다.
입력
이전 줄의 상태와 Review requires CumulativeGreen
결과·효과
관찰 상태 F19-007가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
hash는 XML bytes·사람 설명을 대신하지 않는다
8줄F19-L08 } 출고표 8번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
입력
이전 줄의 상태와 Review requires CumulativeGreen
결과·효과
관찰 상태 F19-008가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
9줄F19-L09 $StatePath = Join-Path $LearnerRoot '.track-learning-stage.json' 출고표 9번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
입력
$StatePath, $LearnerRoot, '.track-learning-stage.json'
결과·효과
관찰 상태 F19-009가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
10줄F19-L10 $Before = Get-Content -Raw -LiteralPath $StatePath | ConvertFrom-Json 출고표 10번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 JSON text를 필드로 접근 가능한 PowerShell object로 바꾼다.
입력
$Before, $StatePath
결과·효과
관찰 상태 F19-010가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
11줄F19-L11 if ($Before.week -ne 25 -or $Before.phase -cne 'CumulativeGreen') { throw 'Review requires CumulativeGreen' } 출고표 11번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 W25부터 현재 주까지 선택 트랙 selector를 누적 실행하는 phase다.
입력
$Before, 25, $Before
결과·효과
관찰 상태 F19-011가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
Review는 Git commit·audio·설명 의미를 자동 검증하지 않는다
13줄F19-L13 $Runner = Join-Path $ReferenceRoot 'scripts\apply-track-learning-stage.ps1' 출고표 13번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
입력
$Runner, $ReferenceRoot, 'scripts\apply-track-learning-stage.ps1'
결과·효과
관찰 상태 F19-013가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
14줄F19-L14 & powershell.exe -NoProfile -ExecutionPolicy Bypass -File $Runner ` 출고표 14번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 W25-D7-review.ps1의 다음 검증 또는 설명 단계를 구성한다.
입력
$Runner
결과·효과
관찰 상태 F19-014가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
15줄F19-L15 -ReferenceRoot $ReferenceRoot -LearnerRoot $LearnerRoot -Week 25 -Phase Review -TimeoutSeconds 1200 출고표 15번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 기존 CumulativeGreen을 전제로 review entry와 leak 경계만 다시 기록한다.
입력
$ReferenceRoot, $LearnerRoot, 25
결과·효과
관찰 상태 F19-015가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
16줄F19-L16 if ($LASTEXITCODE -ne 0) { throw "W25 Review native exit=$LASTEXITCODE" } 출고표 16번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 기존 CumulativeGreen을 전제로 review entry와 leak 경계만 다시 기록한다.
입력
$LASTEXITCODE, 0, "W25 Review native exit=$LASTEXITCODE"
결과·효과
관찰 상태 F19-016가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
Review는 Git commit·audio·설명 의미를 자동 검증하지 않는다
18줄F19-L18 $After = Get-Content -Raw -LiteralPath $StatePath | ConvertFrom-Json 출고표 18번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 JSON text를 필드로 접근 가능한 PowerShell object로 바꾼다.
입력
$After, $StatePath
결과·효과
관찰 상태 F19-018가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
19줄F19-L19 $Entry = @($After.history)[-1] 출고표 19번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 오른쪽 계산 결과를 이름 붙인 PowerShell 변수에 저장한다.
입력
$Entry, $After, 1
결과·효과
관찰 상태 F19-019가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
20줄F19-L20 if ($After.phase -cne 'CumulativeGreen' -or $Entry.phase -cne 'Review') { throw 'Review state mismatch' } 출고표 20번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 W25부터 현재 주까지 선택 트랙 selector를 누적 실행하는 phase다.
입력
$After, 'CumulativeGreen', $Entry
결과·효과
관찰 상태 F19-020가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
21줄F19-L21 if ($Entry.reviewedPhase -cne 'CumulativeGreen' -or $null -ne $Entry.execution) { 출고표 21번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 W25부터 현재 주까지 선택 트랙 selector를 누적 실행하는 phase다.
입력
$Entry, 'CumulativeGreen', $null
결과·효과
관찰 상태 F19-021가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
Review는 Git commit·audio·설명 의미를 자동 검증하지 않는다
22줄F19-L22 throw 'Review must bind prior CumulativeGreen without creating new execution evidence' 출고표 22번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 W25부터 현재 주까지 선택 트랙 selector를 누적 실행하는 phase다.
입력
이전 줄의 상태와 Review requires CumulativeGreen
결과·효과
관찰 상태 F19-022가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
hash는 XML bytes·사람 설명을 대신하지 않는다
23줄F19-L23 } 출고표 23번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 앞에서 연 block 또는 호출 범위를 닫는다.
입력
이전 줄의 상태와 Review requires CumulativeGreen
결과·효과
관찰 상태 F19-023가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
reference와 learner root는 서로 달라야 한다
24줄F19-L24 $Hash = (Get-FileHash -LiteralPath $StatePath -Algorithm SHA256).Hash.ToLowerInvariant() 출고표 24번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 현재 bytes를 64자리 digest로 evidence에 결박한다.
입력
$Hash, $StatePath
결과·효과
관찰 상태 F19-024가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다
25줄F19-L25 "W25_REVIEW_RECORDED track=$($After.track) phase=CumulativeGreen runtime_claim=false state_sha256=$Hash" 출고표 25번 칸을 읽어 다음 검사 칸으로 넘기는 장면 이 줄은 W25부터 현재 주까지 선택 트랙 selector를 누적 실행하는 phase다.
입력
$After, $Hash
결과·효과
관찰 상태 F19-025가 만들어져 뒤 단계의 독립 판정 입력이 된다.
비유의 한계
이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
05

STEP 05 / 13

원본 코드 조각

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

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

F19-C01 · 원문 1–12줄1–12줄
1–12줄 원본
# 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' }
F19-C02 · 원문 13–24줄13–24줄
13–24줄 원본
$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()
F19-C03 · 원문 25–25줄25–25줄
25–25줄 원본
"W25_REVIEW_RECORDED track=$($After.track) phase=CumulativeGreen runtime_claim=false state_sha256=$Hash"
06

STEP 06 / 13

코드 한 줄씩 한국어로 번역

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

전체 번역 23 / 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실행 의미: 입력 경로를 실제 절대 경로로 확인한다.
6if ([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로 바꾼다.
11if ($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 경계만 다시 기록한다.
16if ($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 변수에 저장한다.
20if ($After.phase -cne 'CumulativeGreen' -or $Entry.phase -cne 'Review') { throw 'Review state mismatch' }실행 의미: W25부터 현재 주까지 선택 트랙 selector를 누적 실행하는 phase다.
21if ($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다.
07

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를 서로 대체하지 않는다.

실행 순서

  1. 기본 트랙은 SECURITIES(증권)이며, 명시적 CARD 선택은 기본값을 덮어쓴다. 실제 실행 전 최종 선택 한 개를 selected-track.csv·근거·state에 같은 값으로 기록하고 서로 다른 reference/learner root를 확인한다.
  2. Prepare→VerifyStarter→RecordRed→VerifySolution→RecordGreen→Cumulative→Review 순서를 지킨다.
  3. test를 소유한 세 phase에서만 native exit와 exact JUnit XML 수치를 판정한다.
  4. 다음 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로 연결히토리 → 니지카 → 료 → 키타
  1. 히토리

    reviewedPhase=CumulativeGreen가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 새 Gradle/XML을 만들지 않고 prior CumulativeGreen·leak 경계·history 증가를 확인하며 phase는 CumulativeGreen으로 유지한다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘hash는 XML bytes·사람 설명을 대신하지 않는다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 reviewedPhase=CumulativeGreen와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

08

STEP 08 / 13

실제 값 따라가기

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

순서들어온 값코드가 하는 일나온 값·상태경계
입력Review requires CumulativeGreensource 계약에 대입F19 실행/설명 시작 상태Review는 Git commit·audio·설명 의미를 자동 검증하지 않는다
검증reviewedPhase=CumulativeGreenexpected와 actual 또는 형식 대조통과 또는 첫 mismatchhash는 XML bytes·사람 설명을 대신하지 않는다
증거runtime_claim=falsemarker·hash·row를 같은 run에 연결범위가 적힌 evidence 후보이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
실제 값 — D7 Review — 기존 CumulativeGreen을 reviewedPhase로 연결히토리 → 니지카 → 료 → 키타
  1. 히토리

    phase remains CumulativeGreen가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 새 Gradle/XML을 만들지 않고 prior CumulativeGreen·leak 경계·history 증가를 확인하며 phase는 CumulativeGreen으로 유지한다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘reference와 learner root는 서로 달라야 한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 phase remains CumulativeGreen와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

09

STEP 09 / 13

Gradle·JUnit XML·PowerShell·SQL 내부에서 벌어지는 일

세 test phase, XML bytes archive, Review, 별도 Q41, USER_ATTESTED sealed 결과의 owner와 증명 범위를 구분합니다.

source/contract

W25-D7-review.ps1 bytes와 track·phase·hash 계약을 읽는다.

SECURITIES 기본 선택과 파일 존재·phase 이름만으로 runtime Green을 주장할 수 없다. 실제 selected-track evidence와 실행 결과는 별도다.
execution/evidence

RecordRed·RecordGreen·Cumulative에서만 native exit와 exact JUnit XML을 만든다.

Review는 Git commit·audio·설명 의미를 자동 검증하지 않는다
retention/review

XML bytes를 고유 파일로 보존하고 history hash와 묶은 뒤, Review는 기존 CumulativeGreen만 인용한다. Q41은 별도 PostgreSQL evidence, sealed official status는 user-attested evidence로 남긴다.

이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다
첫 실패 경계 — D7 Review — 기존 CumulativeGreen을 reviewedPhase로 연결히토리 → 니지카 → 료 → 키타
  1. 히토리

    no new execution가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 새 Gradle/XML을 만들지 않고 prior CumulativeGreen·leak 경계·history 증가를 확인하며 phase는 CumulativeGreen으로 유지한다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 no new execution와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

10

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이 생기지 않는다.

11

STEP 11 / 13

이 코드가 보장하지 않는 것

선택 미결정·10_000 finalState·XML 보존·Review/Q41/sealed official truth처럼 이 코드가 책임지지 않는 일을 분리합니다.

증명 범위

Review는 Git commit·audio·설명 의미를 자동 검증하지 않는다

이 책임을 맡는 곳: runtime Gate
증명 범위

hash는 XML bytes·사람 설명을 대신하지 않는다

이 책임을 맡는 곳: external/human review
증명 범위

reference와 learner root는 서로 달라야 한다

이 책임을 맡는 곳: release manifest
증명 범위

기본 트랙은 SECURITIES이며 실제 실행은 정확히 한 트랙에만 귀속한다

이 책임을 맡는 곳: 운영 환경
증명하지 않는 범위 — D7 Review — 기존 CumulativeGreen을 reviewedPhase로 연결히토리 → 니지카 → 료 → 키타
  1. 히토리

    runtime_claim=false가 보이면 바로 완료라고 생각해도 돼? 어떤 입력과 상태를 먼저 확인해야 해?

  2. 니지카

    순서는 source를 읽고 입력을 고정한 뒤 새 Gradle/XML을 만들지 않고 prior CumulativeGreen·leak 경계·history 증가를 확인하며 phase는 CumulativeGreen으로 유지한다. 마지막에 실제 marker와 evidence를 대조하는 거야.

  3. 여기서 멈출 경계는 ‘이 HTML 빌드는 learner Gradle/JUnit을 실행하지 않았다’야. 파일 존재나 문자열 하나를 더 큰 성공으로 확대하면 안 돼.

  4. 키타

    판정은 runtime_claim=false와 실제 exit·row·hash를 같은 실행에 묶는 것. 이 HTML은 코드를 설명하지만 runtime Green을 만들지는 않아.

12

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. 1. 기존 CumulativeGreen을 전제로 review entry와 leak 경계만 다시 기록한다
  2. 2. W25부터 현재 주까지 선택 트랙 selector를 누적 실행하는 phase다
  3. 3. PowerShell 오류를 계속 진행하지 않고 중단시키는 기본 정책을 둔다
  4. 4. 입력 경로를 실제 절대 경로로 확인한다
  5. 5. 입력 경로를 실제 절대 경로로 확인한다
  6. 6. 조건·반복·함수의 실행 block을 연다
  7. 7. 계약 위반을 발견하면 성공 marker 전에 실행을 중단한다
  8. 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 책임을 설명할 수 있나?
13

STEP 13 / 13

전체 원본 source

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

학습용 예시 전체 확인하기 · 정본 답안 아님 · NOT_RUN
학습용 예시 · W25 phase wrapper · 정본 답안 아님 · 로컬 미실행illustrative/powershell/W25-D7-review.ps1SHA-256 cb4a6652ea946bc5c99ca01b4fad18af782bf4a3edb2e4c4e9d3f3998eb832fa
D7 Review — 기존 CumulativeGreen을 reviewedPhase로 연결 전체
# 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"