20주차 미리보기
W20 미리보기 · 웹소설 본편

STARRY PASS 16 — 잠긴 사물함과 네 개의 도장

이름을 아는 것과 남의 것을 열어도 되는 것은 전혀 다른 문제였다

범위개요 + D1–D6 · 월–토p645–681 전부 — W20 개요 + D1–D6
정본 상태SOURCE AUDIT PASSPDF·package·display byte 폐쇄
실행 상태W20 D1–D6 INTEGRATION NOT_RUNtestsExecutedByAudit=0

이 이야기는 p645–681 전부 — W20 개요 + D1–D6만 다룹니다. p682 D7부터, 주간 통합, 공식 참고, W21은 포함하지 않습니다. strict D1–D6 초회 예상시간은 7시간 50분–14시간 50분입니다. 공통 코어 · 트랙 선택 시 증권 기본이며, 증권 전용 기능을 구현하는 주차는 아닙니다. SOURCE AUDIT PASS는 PDF·package·display byte 폐쇄를 확인한 정적 판정일 뿐입니다. 현재 상태는 W20 D1–D6 INTEGRATION NOT_RUN이고 이 preview의 파생 표지는 testsExecutedByAudit=0입니다. source-local @Test 4개는 선언 수이지 실행 수가 아닙니다. 원문 감사의 정확한 실행 경계는 This source audit records source/test/seed oracles; it does not claim Docker/Testcontainers execution Green.이며 learner runtime Green, learner authorship, 모든 거절 audit을 주장하지 않습니다.

월요일 저녁, STARRY 카운터 뒤에 새 사물함 여섯 칸이 놓였다. 손님은 입구에서 이름표를 확인받고 자기 공연카드를 꺼내는 방식이었다. 키타가 시험용 이름표를 대자 화면에 “customer-2”가 떴다. 반짝이는 표시를 본 키타는 가장 가까운 칸의 손잡이를 잡았지만, 그 칸에는 “customer-1”이라고 적혀 있었다.

히토리가 키타의 소매를 잡았다.

“이름은 확인됐는데요. 그게 이 칸의 주인이라는 뜻은 아니지 않나요?”

니지카는 입구 표와 사물함 표를 나란히 놓았다. 첫 표는 authentication, 즉 요청자가 누구인지 확인하는 표였다. 둘째 표는 authorization, 그중에서도 요청한 account의 실제 owner인지 확인하는 object authorization 표였다. 로그인 성공은 첫 문을 통과했다는 뜻일 뿐, 다른 사람의 account를 조회하거나 돈을 움직여도 된다는 만능 열쇠가 아니었다. URL의 account id를 바꿔 남의 자원에 접근하는 위험은 BOLA라는 이름으로 불렸다.

니지카가 태블릿으로 인증·인가·소유권 점검 순서를 확인하는 공식 장면
그림 한눈에: 공식 장면컷은 니지카가 입구 신원표와 사물함 소유표를 나누어 확인하는 분위기용이며, 학습 사건·코드·수치는 원문 감사에 따른 비공식 구성입니다.
요청이 identity permission object owner의 세 단계를 지나며 익명 401 타인 403 invalid 400 본인 200으로 갈리는 도식
그림 한눈에: authentication으로 actor를 확인한 뒤, 서버가 조회한 account owner와 다시 비교해야 남의 사물함을 막을 수 있습니다.

먼저 네 사람은 reference 작업장과 learner 작업장을 서로 다른 절대경로로 나눴다. learner 쪽에 놓인 AccountAuthorization.java starter의 requireOwner는 아무것도 하지 않고 곧바로 돌아왔다. constructor도 repository와 event publisher를 보관하지 않았다. SecurityConfiguration.java starter는 local과 cloud에서 모두 anyRequest().permitAll()이었고 Basic 인증까지 켜 두었다. 두 파일은 안전한 예제가 아니라, 위험한 빈칸을 선명하게 보이게 만든 LEARNER_TARGET_STARTER였다.

료가 permitAll 표지 아래에서 남의 사물함을 열었다. 아무 경고도 울리지 않았다. 키타가 “설치는 잘됐네요!”라며 초록 도장을 들자 세이카가 막았다.

“설치와 안전은 다른 칸이야.”

D1의 expected output은 W20 Starter; provided tests + intentionally incomplete targets installed였다. evidence/w20/bridge-starter.json에는 phase, 실제 path와 source/target hash, ownership이 기록돼야 했다. 하지만 이 문구는 두 starter와 제공 test가 정확한 상대경로에 들어왔다는 뜻일 뿐, 401·403·400·200이나 cloud fail-closed가 Green이라는 뜻이 아니었다. ReferenceRoot와 LearnerRoot가 같다면 작성 주체와 복사 원본을 구분할 수 없으므로 즉시 중단해야 했다.

둘째 날, 니지카는 세 장의 제공 test 계약서를 펼쳤다. CloudFailClosedSecurityIT에는 cloud profile의 health가 200이어야 하고, 학습용 Basic 자격으로 account를 만들려는 POST는 403이어야 하며, WWW-Authenticate header가 없어야 하고 account row 수도 0이어야 한다는 test 한 개가 있었다.

ObjectAuthorizationIT에는 두 test가 있었다. 첫째는 customer-1의 자기 account GET은 200, customer-2의 같은 account GET은 403과 ACCESS_DENIED여야 했다. 둘째는 customer-2가 customer-1의 account에서 이체하려 하면 403이어야 하고, 원 balance 10000TRANSFER business_tx count=0이 그대로여야 했다.

SecurityStatusContractTest에는 같은 route set에서 익명 401, 인증된 타인 403, owner의 invalid opening request 400, owner GET 200을 구분하는 test 한 개가 있었다. 세 source에 선언된 @Test는 모두 4개였다. 그러나 그것은 source inventory였다. 이 미리보기 감사가 실행한 test는 0개였다.

두 intentional Red starter와 세 provided test를 설치한 뒤 tests positive와 두 지정 assertion marker로 exact Red를 기록하는 흐름
그림 한눈에: D1 starter 설치에서 D2 지정 assertion Red, D3 learner solution hash, D4 selector Green으로 이어지고 QA overlay는 옆의 복구 경로로 분리됩니다.

D2의 exact Red marker는 ownerCanReadButAnotherAuthenticatedCustomerCannotanonymous401OtherOwner403Invalid400AndOwner200AreDistinct 두 개였다. tests>0, 두 marker, native_exit!=0이 함께 있어야 했다. import 오류나 문법 오류로 test에 도달하지 못한 실패는 intentional Red가 아니었다. cloud test는 읽어야 할 제공 계약이지만 learner target의 두 exact Red marker 중 하나는 아니었다.

전체 expected 문구는 W20 LearnerRed; native_exit!=0; exact markers=ownerCanReadButAnotherAuthenticatedCustomerCannot;anonymous401OtherOwner403Invalid400AndOwner200AreDistinct였다. 히토리는 길게 이어진 문자열을 종이에 옮겨 적다가 물었다.

“빨갛게 끝났으면 성공이라고 적으면 안 되나요?”

“어디서 넘어졌는지를 봐야 해.” 니지카가 답했다. “문 앞에서 신발끈에 걸린 것과, 잠긴 문이 정말 열리지 않은 건 다른 실패야.”

동일 계좌 fixture에 대해 익명 타인 invalid 본인 요청이 각각 401 403 400 200으로 분리되는 표
그림 한눈에: no auth는 401, authenticated other-owner는 403, owner의 invalid request는 400, owner의 valid read는 200으로 원인을 나눕니다.

네 개의 HTTP status는 점수표가 아니었다. 401은 주체 확인 실패, 403은 확인된 주체의 권한 부족, 400은 권한을 통과한 요청의 입력 계약 위반, 200은 이 test가 고정한 owner 조회 성공이었다. 한 줄의 permitAll이나 한 handler가 네 원인을 섞어 버리면 사용자는 무엇을 고쳐야 하는지 모르고, 운영자는 어디서 정책이 빠졌는지 찾기 어려웠다.

evidence/w20/bridge-recordred.json은 실제 JUnit XML의 지정 실패와 ownership을 담는 주 증거였다. expected 문구를 읽은 것만으로 evidence가 생기지 않았다. 세 test source는 PROVIDED_TEST_CONTRACT였고, 학습자가 고칠 production target 두 개와 저작권 열을 섞을 수 없었다.

셋째 날, 네 사람은 starter 두 개를 직접 고치는 연습에 들어갔다. AccountAuthorization은 request body의 actor 문자열을 믿는 장치가 아니었다. 인증된 principal에서 얻은 actor id와 DB에서 읽은 account owner id를 비교해야 했다. account가 없다면 ACCOUNT_NOT_FOUND, owner가 맞으면 조용히 return, 다른 owner라면 DeniedAuditEvent를 publish한 뒤 ACCESS_DENIED를 던지는 흐름이었다.

네 사람이 객체 소유권과 HTTP status, cloud 경계를 토론하는 공식 장면
그림 한눈에: 공식 장면컷은 네 사람이 principal·DB owner·업무 action의 책임 경계를 토론하는 분위기용입니다.
owner mismatch가 denied audit event를 publish하고 403을 던지는 source는 확인하지만 durable audit selector가 없어 모든 denied audit 완성을 주장하지 않는 도식
그림 한눈에: 타인 owner mismatch에서 event를 publish하고 ACCESS_DENIED를 던지지만, event 발행만으로 durable audit·AFTER_ROLLBACK 저장까지 증명되지는 않습니다.

료가 denied event 종이를 경비 일지 상자에 넣으며 “이제 모든 거절이 영구 보관됐네”라고 말했다. 세이카가 즉시 종이를 다시 꺼냈다. source에는 event publish가 보였지만 W20 exact selector는 모든 denial의 durable audit 저장, exactly-once, 보관 기간, tamper resistance, 저장 실패 정책을 assert하지 않았다. D4에서도 AFTER_ROLLBACK audit 완료를 주장하면 안 됐다.

actor id가 request body에서 오면 공격자가 customer-1이라고 써서 owner 검사를 속일 수 있었다. check와 실제 mutation 사이에 account owner나 상태가 바뀌는 TOCTOU도 별도 transaction·concurrency 설계가 필요했다. receiver account의 소유권과 존재성은 from account의 출금 권한과 같은 규칙이 아니었다. 하나의 requireOwner가 모든 자원·행동 정책을 자동으로 해결하지 않았다.

다음은 SecurityConfiguration이었다. local/test에서는 health를 공개하고 /api/**는 인증을 요구하며 나머지는 거절했다. 학습용 customer-1·customer-2와 {noop}password는 local/test fixture일 뿐 운영 credential이 아니었다. solution source는 익명 요청의 401 JSON에 INVALID_REQUEST, 권한 없는 요청의 403 JSON에 ACCESS_DENIED를 쓰고 requestId를 포함했다. 다만 SecurityStatusContractTest는 401 status만 assert하며 401 body의 errorCode까지 assert하지 않는다.

cloud/prod에서는 health만 공개하고 나머지를 기본 거절했다. Basic은 비활성화했다. 운영 인증이 아직 준비되지 않았다면 연습용 사용자를 외부에 내보내는 대신 API 자체를 fail-closed로 닫는 선택이었다.

cloud profile에서 health는 200이지만 Basic 계좌 생성은 403 challenge 없음 DB write zero가 되는 도식
그림 한눈에: local/test는 health 공개·API 인증·나머지 거절, cloud/prod는 health 외 전부 거절하며 Basic 인증도 열지 않습니다.

이 구성이 production authentication을 제공한다는 뜻은 아니었다. cloud API를 닫았다는 뜻이었다. local API의 CSRF ignore는 완전한 CORS 정책을 증명하지 않았고, 실제 test도 browser origin·preflight 전체를 검사하지 않았다. 문자열로 JSON을 쓰는 helper는 controlled message를 전제로 했으며 임의 사용자 입력 escaping의 일반 해답이 아니었다.

D3 expected output은 W20 LearnerSolutionVerified; exact target hashes=2였다. Red를 확보한 뒤 두 target을 직접 입력한 경로만 learner-authored가 될 수 있었다. 수동 복구 QaSolution --qa-recovery를 쓰면 QA_OVERLAY/VerifiedGreen으로 기록해야 하고 포트폴리오의 learner-authored Green으로 바꿔 적을 수 없었다.

같은 날 Q31 “고객별 잔액 순위”를 풀 계획도 세웠다. Q31 예상시간 35분–1시간은 D3 전체 1시간 40분–3시간 10분에 이미 포함돼 있으므로 주간 합계에 다시 더하지 않았다. shipped workbook 정본 답안은 없었다. illustrative SQL은 customer를 시작 table로 삼아 account가 없는 고객도 total_balance=0으로 남기고, ACTIVE와 CLOSED account를 모두 합산한다는 가정을 공개했다. customer 한 명이 output 한 행이었다.

RANK()DENSE_RANK()는 동점 이후가 달랐다. 100, 100, 50이면 둘 다 앞의 두 행을 공동 1등으로 두지만 다음 행은 RANK 3, DENSE_RANK 2가 됐다. main oracle은 6행, customer6이 total 1000000과 rank/dense rank 1/1, customer4와 customer5가 total 0과 5/5였다. 동점 내부 표시 순서는 customer_id로 안정화했다.

잔액 동률 두 고객 다음 행이 RANK 3 DENSE RANK 2가 되며 본 예시 결과 여섯 행을 갖는 순위 도식
그림 한눈에: 100·100·50에서 RANK는 1·1·3, DENSE_RANK는 1·1·2가 되고 계좌 없는 고객도 0으로 보존합니다.

이 SQL은 학습용 예시 · 정본 답안 아님이었다. CLOSED account 포함, 계좌 없는 고객 보존, 순위 grain은 prompt가 고정하지 않은 부분을 예시가 명시한 가정이었다. evidence/w20/sql-q31.sql은 learner가 자기 query를 실제 PostgreSQL fixture에서 실행하고 table grain·cardinality·반례를 연결할 때 생기는 증거였다.

넷째 날에는 두 learner solution과 제공 cloud fixture를 함께 검증할 계획표가 나왔다. D4의 Green selector는 ObjectAuthorizationIT, SecurityStatusContractTest, CloudFailClosedSecurityIT 세 개였다. 실제 RecordGreen이라면 새 JUnit XML에서 tests>0, failures·errors·skipped=0, native exit=0을 확인해야 했다.

D4는 세 security selector D5는 object authorization 하나 D6는 status contract 하나를 정확히 실행하는 표
그림 한눈에: D4는 세 selector, D5는 ObjectAuthorizationIT 하나, D6은 SecurityStatusContractTest 하나이며 인쇄 source 목록과 실행 selector 목록을 섞지 않습니다.

키타가 세 selector 옆에 “우리가 만든 세 파일”이라고 쓰려 하자 히토리가 지웠다. learner target은 AccountAuthorization.javaSecurityConfiguration.java 두 개였다. 세 test는 제공 계약이고 cloud test와 build append는 provided fixture였다. selector Green은 실행 상태이고 ownership은 source 작성 주체였다. 두 열은 독립적이었다.

D4 expected output은 W20 LearnerGreen for learner-typed path OR VerifiedGreen source_mode=QA_OVERLAY for recovery path였다. 앞 경로는 Red 뒤 직접 입력한 두 target의 learner path, 뒤 경로는 수동 복구 source mode였다. evidence/w20/bridge-recordgreen.json에는 어느 길을 택했는지 숨기지 않아야 했다.

세 selector가 함께 Green이더라도 claim은 object authorization, 401·403·400·200 구분, cloud health-only fail-closed에 한정됐다. provided DeniedAuditEvent가 source에서 publish된다는 이유로 모든 denied audit 저장이 검증됐다고 넓힐 수 없었다. selector 목록에 없는 AFTER_ROLLBACK, dual control, 전체 endpoint enumeration, real cloud identity를 덧붙이지 않았다.

니지카는 “검사한 이름을 그대로 결과표 제목으로 쓰자”고 했다. 확인한 것보다 넓은 문구는 보기에는 든든하지만, 다음 사람이 실제 빈칸을 찾지 못하게 만들었다.

다섯째 날, 료는 히토리의 시험 account id를 URL에 넣고 조회했다. customer-2로 로그인했기 때문에 authentication은 성공했지만 owner는 customer-1이었다. GET은 403으로 멈췄다. 이어서 같은 account에서 1000을 보내려는 transfer도 403으로 멈췄다.

카운터에 모인 네 사람이 selector Green과 정적 감사의 한계를 정리하는 공식 장면
그림 한눈에: 공식 장면컷은 카운터에서 owner 요청과 other-owner 요청의 status·업무 상태를 함께 확인하는 분위기용입니다.
customer 2가 customer 1 계좌를 읽거나 이체하려 할 때 owner 검사에서 403이 되고 잔액과 거래 수가 유지되는 도식
그림 한눈에: owner GET은 200, 타인 GET·transfer는 403이며 거절 뒤 source balance 10000과 TRANSFER row 0이 그대로입니다.

거절 화면만 확인하고 끝내지 않았다. 시작 balance는 10000이었고 거절 뒤에도 10000이어야 했다. business_tx에서 TRANSFER count도 0이어야 했다. 403을 반환한 뒤 내부에서 돈이나 거래 row가 바뀐다면 겉만 잠긴 거짓 Green이었다.

D5 exact selector는 ObjectAuthorizationIT 하나였다. expected 형식은 EXACT_SELECTOR_GREEN selectors=1 classes>=1 tests>=1 failures=0 errors=0 skipped=0 native_exit=0, 주 증거는 evidence/w20/day-5-selector-gate.json이었다. 이 두 test가 증명한 것은 owner read 200, other read/transfer 403, 특정 balance와 TRANSFER row 불변이다. 모든 downstream table, receiver 정책, concurrent owner change, owner transfer success를 전부 증명하지는 않았다.

같은 날 Q32 “계좌별 원장 누적합”도 계획했다. Q32 예상시간 35분–1시간은 D5 전체 1시간 30분–2시간 50분에 이미 포함돼 있으므로 주간 합계에 다시 더하지 않았다. illustrative SQL은 ledger_entry 한 행을 signed movement의 권위 grain으로 보고, account별로 SUM(signed_amount) OVER (...)를 계산했다. 정렬은 occurred_at, entry_id였고 frame은 ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW였다. 같은 시각의 두 entry도 entry_id로 고정해야 결과가 흔들리지 않았다.

account 101의 7단계 누계 10000 11000 10500 10200 10000 9400 8800과 같은 시각 reversal entry 15 다음 entry 16의 안정 순서를 모두 표시한 도식
그림 한눈에: account별 ledger row를 occurred_at·entry_id 순서로 놓고 ROWS 누적합을 계산해 같은 시각의 tie도 안정화합니다.

oracle은 전체 16행이었다. account101의 누계는 10000, 11000, 10500, 10200, 10000, 9400, 8800, account102는 20000, 20300이었다. account101의 같은 시각 reversal은 entry15 뒤 entry16 순서였다. ledger row가 없는 account는 나오지 않았고, 이 query 자체는 마지막 누계와 account.balance를 reconciliation하지 않았다.

Q32도 shipped workbook answer가 아니었다. ledger를 권위 원장으로 보는 가정, 0-row account 제외, tie order가 명시된 illustrative example이었다. evidence/w20/sql-q32.sql은 실제 실행 성공, opening entry부터의 누계, input/output grain, 예상 cardinality, 반례가 함께 있어야 했다.

여섯째 날, 네 사람은 네 가지 도장을 한 번 더 꺼냈다. no auth 요청에는 401, customer-2가 customer-1 account를 읽으면 403, customer-1이 opening balance 0을 보내면 400, customer-1이 자기 account를 읽으면 200이었다. D6 exact selector는 SecurityStatusContractTest 하나였다.

그런데 p676–679에 전문으로 인쇄된 source는 CloudFailClosedSecurityIT, ObjectAuthorizationIT, SecurityStatusContractTest 세 개였다. 인쇄된 세 source가 D6 exact selector 세 개라는 뜻은 아니었다. 반대로 D6 selector가 하나라고 나머지 두 source가 존재하지 않는다는 뜻도 아니었다. 실행 대상과 학습용 display 목록을 다른 표로 읽어야 했다.

D6 expected 형식은 EXACT_SELECTOR_GREEN selectors=1 classes>=1 tests>=1 failures=0 errors=0 skipped=0 native_exit=0이었다. 주 evidence는 evidence/w20/day-6-selector-gate.json이고, evidence/w20/security-status.md에는 실제 실행 날짜·report 경로·native exit·오늘 새로 쓴 파일을 기록해야 했다. source의 실제 상대경로와 package도 맞아야 했다.

그러나 SecurityStatusContractTest의 한 method가 직접 assert하는 것은 네 status와 두 errorCode뿐이었다. test는 invalid POST나 other GET 뒤 DB write count를 assert하지 않았다. 따라서 D6 selector가 “모든 거절 path write0”을 자동으로 증명한다고 쓰지 않았다. D5의 ObjectAuthorizationIT가 확인한 특정 transfer no-effect를 D6 status test의 proof로 옮겨 붙일 수도 없었다.

또 D6 핵심 개념·본문에 CORS·CSRF가 언급된다고 완전한 browser-origin 정책이 검증된 것은 아니었다. preflight, allowlist, credentialed origin, 모든 controller body schema, 모든 exception mapping은 이 selector의 직접 assertion 밖이었다. solution source는 401 JSON에 INVALID_REQUEST를 쓰지만 SecurityStatusContractTest는 401 status만 assert하고 그 errorCode는 assert하지 않는다. 따라서 source 구현 선택을 test assertion이나 모든 API의 보편 규칙으로 바꾸지 않았다.

여섯 장의 계획표 아래 시간을 더했다. D1 55분–1시간 45분, D2 1시간 5분–2시간 5분, D3 1시간 40분–3시간 10분, D4 1시간 5분–2시간 10분, D5 1시간 30분–2시간 50분, D6 1시간 35분–2시간 50분이었다. strict D1–D6 합계는 정확히 7시간 50분–14시간 50분이었다. W20 개요의 8시간 35분–16시간 20분은 이 범위 밖의 다음 모듈 45–90분까지 포함한 값이므로 서로 바꿔 쓰지 않았다.

modern 코드 뒤풀이의 display closure는 canonical 7개illustrative 2개였다. canonical은 intentional Red starter 2개, provided test source 3개, Green solution reference 2개였다. illustrative는 Q31·Q32 SQL 두 개였다. content aggregate vector 9/359/327/79/248/327/33/4는 teaching units 9 / physical lines 359 / nonblank lines 327 / setup lines 79 / mapping rows 248 / translation rows 327 / source chunks 33 / source-local tests 4를 뜻했다.

source audit pass가 확인한 PDF package display closure와 확인하지 않은 integration learner authorship every denied audit를 나눈 도식
그림 한눈에: canonical 7·illustrative 2와 source-local test 4를 세되, 실제 실행 0·learner authorship 미확인·모든 denied audit 미증명을 별도 경계로 둡니다.

source-local @Test 4개는 세 제공 source에 선언된 method 수이지 이 감사의 실행 결과가 아니었다. SOURCE AUDIT PASS는 PDF/package/display closure가 byte로 닫혔다는 뜻이었다. 정확한 경계는 PDF/package/display closure is byte-verified; PASS does not claim Docker Green, learner authorship, or every denied audit.였다. 실제 runtime Green은 learner workspace의 fresh JUnit XML, native exit, source hash, source mode와 사람 검토가 필요했다.

니지카는 p681의 D6 최종 Gate에서 장부를 닫았다. 다음 페이지부터 시작되는 D7, 주간 통합, 공식 참고, W21의 내용은 이 미리보기 안으로 들이지 않았다. 히토리는 네 도장을 다시 바라봤다. 401·403·400·200은 사람의 등급이 아니라 요청이 멈춘 문을 알려 주는 표지였다.

잠긴 사물함은 불친절한 장치가 아니었다. 이름을 확인한 사람에게도 자기 것만 열어 주고, 거절된 요청은 돈과 거래를 바꾸지 않으며, 준비되지 않은 외부 문은 닫아 두는 약속이었다. 무엇을 test했고 무엇을 쓰지 않았는지까지 구분하자, STARRY의 열쇠표는 비로소 믿을 만해졌다.

이미지 출처와 이용 안내: 공식 장면컷은 TV 애니메이션 《봇치 더 록!》 공식 사이트 자료입니다. ©はまじあき/芳文社・アニプレックス. 이 문서는 개인 학습용 비공식 구성으로, 원작의 공식 설정과 별개의 학습 비유입니다. 개념도는 W20 source audit의 수치·ownership·미보장 경계에 맞춰 새로 만든 교육용 SVG입니다.

W20 미리보기 · 히토리 질문 노트

히토리의 질문 노트 — STARRY PASS 16

본편의 사물함 비유를 W20 object authorization·HTTP status·cloud fail-closed의 정확한 source 역할과 증거 경계로 다시 연결합니다. 모든 답은 p645–681 전부 — W20 개요 + D1–D6에 한정합니다. 현재 상태는 W20 D1–D6 INTEGRATION NOT_RUN이고 이 preview의 파생 표지는 testsExecutedByAudit=0입니다. expected marker를 실제 실행 Green으로 바꾸어 읽지 않습니다.

1. 이번 미리보기의 strict PDF 범위는 어디인가요?

답: p645의 W20 heading부터 시작하는 개요 전체에서 p681의 D6 최종 Gate까지입니다.

근거: 정확한 범위 표기는 p645–681 전부 — W20 개요 + D1–D6입니다. p645의 W20 heading을 포함한 개요 전체에서 시작하고, p682에서 새로 시작하는 D7과 그 뒤 주간 통합·공식 참고·W21은 포함하지 않습니다.

오답 함정: modern 코드 문서가 W20 전체를 감사했다는 이유로 D7이나 주간 통합 내용을 이 D1–D6 미리보기에 섞으면 안 됩니다.

범위 한계: 페이지 번호만 같다고 의미 경계가 자동으로 정해지는 것은 아닙니다. heading과 모듈 전환을 함께 확인해야 합니다.

실제 기술 이름semantic PDF boundary for W20 overview and D1–D6

2. D1–D6의 초회 예상시간 합계와 기본 트랙은 무엇인가요?

답: 합계는 7시간 50분–14시간 50분, 즉 470–890분이며 공통 코어 · 트랙 선택 시 증권 기본입니다.

근거: D1 55–105분, D2 65–125분, D3 100–190분, D4 65–130분, D5 90–170분, D6 95–170분을 더합니다. W20은 권한·API 안전성 공통 코어이며 트랙 선택 UI에서는 증권을 기본값으로 둡니다.

오답 함정: 개요의 8시간 35분–16시간 20분을 strict 합계로 쓰면 범위 밖 다음 모듈 45–90분이 더해집니다.

범위 한계: 예상시간은 active-time 계획값이고 실제 시간, 막힘 중단선, 24–72시간 재검증 시간과 같지 않습니다.

실제 기술 이름bounded active-time total with default securities track metadata

3. SOURCE AUDIT PASS를 현재 runtime Green이라고 말할 수 있나요?

답: 아니요. PASS는 PDF·package·display closure의 byte 검증이고 현재 상태는 W20 D1–D6 INTEGRATION NOT_RUN입니다.

근거: source audit의 문구는 PDF/package/display closure is byte-verified; PASS does not claim Docker Green, learner authorship, or every denied audit.입니다. 실행 경계도 This source audit records source/test/seed oracles; it does not claim Docker/Testcontainers execution Green.이라고 명시합니다.

오답 함정: source hash와 expected output이 문서에 있다는 이유만으로 learner workspace의 새 JUnit XML, native exit, source mode가 확인됐다고 쓰면 안 됩니다.

범위 한계: 이 preview의 testsExecutedByAudit=0은 실행하지 않았음을 가시화한 파생 표지입니다. 실제 Green은 별도 실행 evidence가 필요합니다.

실제 기술 이름byte-verified source closure versus unexecuted integration evidence

4. authentication과 object authorization은 왜 별도 문인가요?

답: authentication은 actor가 누구인지 확인하고, object authorization은 그 actor가 요청한 account의 실제 owner이거나 허용된 주체인지 판단하기 때문입니다.

근거: customer-2가 정상 로그인했어도 customer-1 소유 account를 읽거나 출금할 권한은 없습니다. 서버가 DB owner를 읽고 인증 principal과 비교해야 합니다.

오답 함정: 로그인 성공을 모든 account id에 대한 허용으로 바꾸면 URL id를 바꿔 남의 자원을 여는 BOLA 취약점이 생깁니다.

범위 한계: 한 account의 owner 검사만으로 receiver account, operator 권한, 공동 소유, 모든 action 정책이 자동 완성되지는 않습니다.

실제 기술 이름authentication-separated object-level authorization for BOLA prevention

요청이 identity permission object owner의 세 단계를 지나며 익명 401 타인 403 invalid 400 본인 200으로 갈리는 도식
그림 한눈에: actor 확인과 account owner 비교를 두 문으로 나누어 로그인만으로 남의 자원이 열리지 않게 합니다.

5. D1의 두 starter는 무엇이 의도적으로 위험한가요?

답: AccountAuthorizationrequireOwner는 아무 검사 없이 return하고, SecurityConfiguration은 local과 cloud 모두 permitAll이며 Basic까지 켭니다.

근거: constructor는 repository와 event publisher를 보관하지 않고 missing account·other owner·denied event를 처리하지 않습니다. security starter는 어느 profile에서도 API를 잠그지 않습니다.

오답 함정: source가 canonical package에 있다는 이유로 안전한 정답이라고 읽으면 안 됩니다. canonical은 출처가 정본이라는 뜻이고 starter는 intentional Red 역할입니다.

범위 한계: starter 설치는 학습 출발점일 뿐 401·403·400·200이나 cloud write0의 관찰 결과가 아닙니다.

실제 기술 이름canonical intentional Red production targets

6. ReferenceRoot와 LearnerRoot, bridge-starter evidence는 어떻게 읽나요?

답: 두 root를 다른 절대경로로 두고 두 incomplete target과 제공 test의 실제 path·hash·ownership을 evidence/w20/bridge-starter.json에 기록합니다.

근거: D1 expected output은 W20 Starter; provided tests + intentionally incomplete targets installed입니다. 동일 root, target 누락, solution body 선설치, ownership/hash 누락은 fail-closed 대상입니다.

오답 함정: expected 문자열을 복사하거나 기존 파일이 있다는 사실만으로 오늘의 starter evidence를 만들었다고 세면 안 됩니다.

범위 한계: root 분리와 hash 일치는 저작·기능 Green을 단독으로 증명하지 않습니다. D2 Red와 D3 직접 입력이 이어져야 합니다.

실제 기술 이름isolated learner-root starter provenance gate

7. D2에서 읽는 test source와 source-local method 수는 어떻게 되나요?

답: CloudFailClosedSecurityIT 1개, ObjectAuthorizationIT 2개, SecurityStatusContractTest 1개로 총 4개의 @Test method가 선언돼 있습니다.

근거: 세 파일은 모두 PROVIDED_TEST_CONTRACT입니다. sourceLocalTests=4는 source inventory의 선언 수입니다.

오답 함정: 선언된 네 method를 이 audit에서 실행한 네 test라고 읽으면 testsExecutedByAudit=0과 source audit의 실행 비주장 문구에 어긋납니다.

범위 한계: method 수만으로 assertion 수, endpoint 전수검사, 업무 정책 전체의 coverage를 판단할 수 없습니다.

실제 기술 이름provided test inventory with four source-local methods

8. D2 intentional Red와 우연한 compile 실패를 어떻게 구분하나요?

답: 두 지정 assertion marker에 실제로 도달해 실패하고 tests>0·native_exit!=0인지 함께 확인합니다.

근거: 전체 expected 문구는 W20 LearnerRed; native_exit!=0; exact markers=ownerCanReadButAnotherAuthenticatedCustomerCannot;anonymous401OtherOwner403Invalid400AndOwner200AreDistinct입니다.

오답 함정: import 오류, 문법 오류, test discovery 0건, unrelated cloud failure를 intentional Red success로 세면 learner target의 빈 동작을 관찰하지 못합니다.

범위 한계: marker 문자열을 읽은 것과 fresh JUnit XML 및 evidence/w20/bridge-recordred.json을 만든 것은 다릅니다.

실제 기술 이름assertion-reached exact Red gate

두 intentional Red starter와 세 provided test를 설치한 뒤 tests positive와 두 지정 assertion marker로 exact Red를 기록하는 흐름
그림 한눈에: starter 설치, 지정 assertion Red, learner hash 검증, selector Green을 순서대로 놓고 QA overlay를 별도 복구선으로 둡니다.

9. ObjectAuthorizationIT는 무엇을 직접 확인하고 무엇을 남기나요?

답: owner GET 200, authenticated other-owner GET 403과 ACCESS_DENIED, other-owner transfer 403, source balance 10000, TRANSFER row 0을 확인합니다.

근거: 첫 method는 read ownership을, 둘째 method는 denied transfer의 특정 no-effect를 assert합니다. fixture는 customer-1 소유 account 10000과 customer-2 receiver 5000입니다.

오답 함정: 이 두 test로 모든 downstream table, receiver authorization, owner transfer success, concurrent ownership change가 검증됐다고 넓히면 안 됩니다.

범위 한계: denied audit persistence는 이 test의 직접 assertion이 아닙니다.

실제 기술 이름object authorization integration contract with bounded denial invariants

10. SecurityStatusContractTest의 네 칸은 어떤 원인을 구분하나요?

답: no auth 401, authenticated other-owner 403, owner의 invalid opening request 400, owner의 valid account read 200을 구분합니다.

근거: 403 body의 errorCode는 ACCESS_DENIED, 400 body는 INVALID_REQUEST를 확인합니다. 한 route set에서 identity·permission·validation·success를 분리합니다.

오답 함정: 401과 403을 모두 “로그인 오류”로 부르거나 invalid input을 권한 실패로 바꾸면 실패 원인과 handler 책임이 섞입니다.

범위 한계: solution source는 401 JSON에 INVALID_REQUEST를 쓰지만 이 method는 401 status만 assert하고 그 errorCode는 assert하지 않습니다. 직접 확인하는 body errorCode는 403의 ACCESS_DENIED와 400의 INVALID_REQUEST이며, 모든 controller·response field·rejection write0도 보장하지 않습니다.

실제 기술 이름HTTP 401/403/400/200 security-status matrix

동일 계좌 fixture에 대해 익명 타인 invalid 본인 요청이 각각 401 403 400 200으로 분리되는 표
그림 한눈에: 요청이 authentication·ownership·validation 문을 어디까지 통과했는지 네 status로 구분합니다.

11. CloudFailClosedSecurityIT가 증명하는 cloud 경계는 어디까지인가요?

답: health GET 200, Basic을 붙인 account POST 403, WWW-Authenticate 없음, account count 0을 한 unsafe endpoint에서 확인합니다.

근거: cloud/prod solution은 health 외 모든 요청을 deny하고 Basic을 disable합니다. 준비되지 않은 운영 인증 대신 API를 닫는 fail-closed 설계입니다.

오답 함정: 이 Green을 production authentication 구축, 모든 endpoint 전수거절, 완전한 CORS·network policy로 부르면 안 됩니다.

범위 한계: audit row, browser preflight, real identity provider, 다른 모든 write endpoint는 test의 직접 assertion 밖입니다.

실제 기술 이름health-only cloud profile fail-closed contract

cloud profile에서 health는 200이지만 Basic 계좌 생성은 403 challenge 없음 DB write zero가 되는 도식
그림 한눈에: local/test의 학습용 인증 경계와 cloud/prod의 health-only disabled API를 다른 문으로 둡니다.

12. D3 learner solution과 QA overlay는 어떻게 구분하나요?

답: Red 뒤 학습자가 AccountAuthorization.javaSecurityConfiguration.java를 직접 입력하고 두 exact hash를 맞춘 경로만 learner-authored입니다.

근거: D3 expected output은 W20 LearnerSolutionVerified; exact target hashes=2입니다. QaSolution --qa-recovery를 쓰면 최종 source mode는 QA_OVERLAY/VerifiedGreen입니다.

오답 함정: reference solution을 복사해 hash가 맞았다는 이유로 포트폴리오에 learner-authored Green이라고 쓰면 안 됩니다.

범위 한계: hash 검증은 byte identity를 확인하지만 이해도·독립 재현·runtime Green을 혼자 증명하지 않습니다.

실제 기술 이름learner-typed hash verification with explicit QA recovery provenance

13. AccountAuthorization solution의 실제 분기와 책임은 무엇인가요?

답: DB owner 조회가 비면 ACCOUNT_NOT_FOUND, owner가 actor와 같으면 return, 다르면 denied event를 publish한 뒤 ACCESS_DENIED를 던집니다.

근거: repository에서 찾은 owner와 trusted principal의 actor id를 비교합니다. action과 requestId는 denied event의 추적 맥락으로 전달됩니다.

오답 함정: path나 request body의 owner 값을 신뢰하거나 account missing을 403과 뭉개면 서버 권위 데이터와 오류 계약이 흐려집니다.

범위 한계: to account 정책, operator 역할, 공동 소유, 다른 resource type은 이 method의 직접 책임이 아닙니다.

실제 기술 이름service-boundary owner lookup and denial policy

14. denied event가 보인다고 durable audit까지 Green인가요?

답: 아닙니다. source에서 event publish가 보이는 것과 transaction 종료 뒤 audit row가 내구성 있게 남는 것은 다른 증거입니다.

근거: W20 exact selector는 모든 denial의 audit persistence, AFTER_ROLLBACK, exactly-once, retention, tamper resistance, 저장 실패 정책을 직접 assert하지 않습니다. actor id도 request body가 아니라 authenticated principal에서 와야 합니다.

오답 함정: DeniedAuditEvent constructor 한 줄을 보고 “모든 거절이 안전하게 보관됨”이라고 결론 내리거나 check 뒤 mutation 사이의 TOCTOU를 무시하면 안 됩니다.

범위 한계: durable audit과 authorization/mutation의 일관성은 별도 transaction·concurrency·storage test가 필요합니다.

실제 기술 이름event-publication versus durable-audit and TOCTOU boundary

owner mismatch가 denied audit event를 publish하고 403을 던지는 source는 확인하지만 durable audit selector가 없어 모든 denied audit 완성을 주장하지 않는 도식
그림 한눈에: mismatch event publish와 ACCESS_DENIED는 보이지만 durable audit·AFTER_ROLLBACK·동시성 보장은 미검증으로 남습니다.

15. SecurityConfiguration의 profile별 경계와 보안 caveat는 무엇인가요?

답: local/test는 health 공개, /api/** 인증, 나머지 deny이고, cloud/prod는 health 외 모두 deny하며 Basic을 끕니다.

근거: local의 customer-1·customer-2와 {noop}password는 학습 fixture입니다. cloud는 운영 인증을 제공하는 대신 준비되지 않은 API를 disabled 상태로 둡니다.

오답 함정: local CSRF ignore를 완전한 CORS 정책으로 보거나 학습용 Basic user를 운영 credential로 재사용하면 안 됩니다.

범위 한계: preflight, credentialed origin, allowlist, JSON escaping 일반성, network identity는 별도 검증 영역입니다.

실제 기술 이름profile-specific Spring SecurityFilterChain with fail-closed production posture

16. Q31 illustrative SQL은 어떤 grain·순위·oracle을 사용하나요?

답: customer 한 명을 output grain으로 두고 모든 ACTIVE/CLOSED account balance를 합산하며, 계좌 없는 고객도 0으로 보존한 뒤 RANK와 DENSE_RANK를 함께 계산합니다.

근거: main 결과는 6행입니다. customer6은 total 1000000·rank/dense 1/1이고, customer4와 customer5는 total 0·rank/dense 5/5입니다. tie probe 100,100,50의 마지막은 RANK 3·DENSE_RANK 2입니다. Q31 예상시간 35분–1시간은 D3 총시간에 이미 포함되므로 다시 더하지 않습니다.

오답 함정: INNER JOIN으로 zero-account customer를 지우거나 RANK와 DENSE_RANK를 같은 함수로 설명하거나 CLOSED account를 몰래 제외하면 예시 계약이 달라집니다.

범위 한계: 이 파일은 canonicalAnswerShipped=false인 audit-authored illustrative SQL입니다. 포함 status와 0-account 보존은 명시한 가정입니다.

실제 기술 이름customer-grain balance aggregation with RANK and DENSE_RANK

잔액 동률 두 고객 다음 행이 RANK 3 DENSE RANK 2가 되며 본 예시 결과 여섯 행을 갖는 순위 도식
그림 한눈에: 동점 뒤 번호를 건너뛰는 RANK와 붙여 세는 DENSE_RANK를 zero-account 보존과 함께 봅니다.

17. D4 RecordGreen의 selector·증거·실행 조건은 무엇인가요?

답: ObjectAuthorizationIT, SecurityStatusContractTest, CloudFailClosedSecurityIT 세 selector를 fresh JUnit XML로 검증합니다.

근거: tests>0, failures/errors/skipped=0, native exit=0을 확인하고 evidence/w20/bridge-recordgreen.json에 source mode와 ownership을 남깁니다. expected output은 W20 LearnerGreen for learner-typed path OR VerifiedGreen source_mode=QA_OVERLAY for recovery path입니다.

오답 함정: 이전 XML이나 state file만 읽거나 QA_OVERLAY를 LearnerGreen으로 기록하면 실행 freshness와 authorship이 모두 흐려집니다.

범위 한계: 세 selector의 직접 assertion 밖인 audit durability·CORS 전체·real cloud auth는 Green claim에 들어가지 않습니다.

실제 기술 이름three-selector RecordGreen gate with explicit source mode

D4는 세 security selector D5는 object authorization 하나 D6는 status contract 하나를 정확히 실행하는 표
그림 한눈에: D4 세 selector와 D5·D6 단일 selector를 나누고 learner target 두 개와 provided test 세 개의 ownership도 분리합니다.

18. D4에서 Green 상태와 source ownership은 왜 별도 열인가요?

답: selector Green은 test 실행 결과이고 ownership은 누가 어떤 source를 작성·제공했는지에 대한 provenance이기 때문입니다.

근거: learner target은 AccountAuthorization과 SecurityConfiguration 두 파일입니다. 세 test는 provided contract이고 CloudFailClosedSecurityIT와 build append는 provided fixture입니다.

오답 함정: 세 selector가 Green이라는 이유로 “learner가 세 test와 모든 보안 기능을 만들었다”고 쓰면 안 됩니다.

범위 한계: learner-typed 표지도 실제 Red 이후 직접 입력 기록·hash·source mode가 있어야 의미가 있습니다.

실제 기술 이름execution-state and source-authorship separation

19. D4 Green에서 제외해야 할 audit·운영 과대주장은 무엇인가요?

답: every denied audit, durable persistence, AFTER_ROLLBACK, exactly-once, dual control, production identity, 모든 endpoint coverage를 완료했다고 말하면 안 됩니다.

근거: 세 selector는 object ownership, 한 status matrix, 한 cloud unsafe endpoint의 health-only fail-closed를 직접 확인합니다. source audit 자체도 every denied audit을 주장하지 않습니다.

오답 함정: security라는 큰 제목을 test의 좁은 assertion보다 넓은 보증으로 바꾸면 남은 위험을 숨깁니다.

범위 한계: 추가 claim에는 그 기능을 직접 겨냥한 selector, 상태 전후 invariant, 운영 환경 evidence가 필요합니다.

실제 기술 이름selector-bounded security claim discipline

20. D4 evidence에서 learner path와 recovery path를 어떻게 읽나요?

답: learner-typed path는 W20 LearnerGreen, 수동 복구는 VerifiedGreen source_mode=QA_OVERLAY로 읽습니다.

근거: bridge-recordgreen.json은 exact selectors의 새 결과와 두 learner target·provided fixture의 ownership을 함께 기록해야 합니다.

오답 함정: recovery source가 같은 test를 통과했다는 이유로 저작 경계를 지우거나 expected output 문자열만 evidence로 남기면 안 됩니다.

범위 한계: 어느 path든 이 preview에서는 실행하지 않았으므로 현재 learner workspace의 상태를 보증하지 않습니다.

실제 기술 이름provenance-preserving Green evidence bifurcation

21. D5 exact selector와 관찰할 no-effect는 무엇인가요?

답: exact selector는 ObjectAuthorizationIT 하나이며 owner GET 200, other-owner GET·transfer 403, 최종 balance 10000, TRANSFER count 0을 봅니다.

근거: expected 형식은 EXACT_SELECTOR_GREEN selectors=1 classes>=1 tests>=1 failures=0 errors=0 skipped=0 native_exit=0이고 주 증거는 evidence/w20/day-5-selector-gate.json입니다.

오답 함정: 과거 제목을 따라 SQL injection test라고 부르거나 403 status만 보고 DB invariant를 생략하면 안 됩니다.

범위 한계: no-effect는 이 fixture의 source balance와 TRANSFER row에 한정됩니다. 모든 table·side effect를 전수 증명하지 않습니다.

실제 기술 이름single-selector BOLA regression with bounded business no-effect

22. 403과 write0을 함께 보는 이유는 무엇인가요?

답: 외부 응답만 403이고 내부 balance나 transaction row가 바뀌면 권한 거절이 업무 효과를 막지 못한 거짓 Green이기 때문입니다.

근거: customer-2의 unauthorized transfer 뒤 customer-1 account balance는 10000, TRANSFER business_tx count는 0이어야 합니다.

오답 함정: controller에서 403을 썼다는 사실만 확인하거나, 모든 downstream 상태가 자동 rollback됐다고 추정하면 안 됩니다.

범위 한계: receiver balance, ledger, audit event, external message, concurrency는 별도 assertion이 없으면 claim할 수 없습니다.

실제 기술 이름response-and-state dual assertion for denial invariants

customer 2가 customer 1 계좌를 읽거나 이체하려 할 때 owner 검사에서 403이 되고 잔액과 거래 수가 유지되는 도식
그림 한눈에: 타인 요청의 403과 함께 source balance·TRANSFER row를 전후 비교해 겉만 잠긴 실패를 찾습니다.

23. Q32 running-sum SQL은 어떤 window와 oracle을 사용하나요?

답: ledger_entry를 signed movement grain으로 두고 account별 SUM(signed_amount) OVERoccurred_at, entry_id 순서의 ROWS frame으로 계산합니다.

근거: 전체 16행, account101 누계는 10000,11000,10500,10200,10000,9400,8800이고 account102는 20000,20300입니다. 같은 시각 account101 reversal은 entry15 뒤 entry16입니다. Q32 예상시간 35분–1시간은 D5 총시간에 이미 포함되므로 다시 더하지 않습니다.

오답 함정: occurred_at만 정렬하거나 default RANGE 의미를 무시하면 같은 시각 행의 누적 순서가 불안정해질 수 있습니다.

범위 한계: ledger row가 없는 account는 나오지 않고 query 자체는 최종 running balance와 account.balance를 reconciliation하지 않습니다.

실제 기술 이름deterministic account-partitioned ROWS running sum

account 101의 7단계 누계 10000 11000 10500 10200 10000 9400 8800과 같은 시각 reversal entry 15 다음 entry 16의 안정 순서를 모두 표시한 도식
그림 한눈에: occurred_at 동률을 entry_id로 끊어 physical row 단위 누적합을 안정적으로 만듭니다.

24. Q31·Q32를 정본 답안이라고 부르면 안 되는 이유는 무엇인가요?

답: workbook에 shipped canonical answer가 없고 두 SQL은 pinned schema·seed와 명시한 가정으로 만든 illustrative example이기 때문입니다.

근거: Q31은 ACTIVE/CLOSED 포함과 zero-account 보존, Q32는 ledger authority·zero-row account 제외·stable tie order를 공개합니다. 둘 다 canonicalAnswerShipped=false입니다.

오답 함정: oracle 숫자가 맞는다는 이유로 업무 요구사항의 빈칸까지 확정됐거나 learner 제출 정답이라고 부르면 안 됩니다.

범위 한계: 실제 과제 evidence는 learner가 자기 query를 실행하고 시작 table·grain·cardinality·반례를 설명해야 합니다.

실제 기술 이름noncanonical illustrative SQL with explicit assumptions

25. D6 exact selector와 인쇄된 source 목록은 어떻게 다른가요?

답: D6 exact selector는 SecurityStatusContractTest 하나지만 p676–679에 전문으로 인쇄된 source는 CloudFailClosedSecurityIT·ObjectAuthorizationIT·SecurityStatusContractTest 세 개입니다.

근거: 실행 command와 expected 형식은 selectors=1입니다. 세 source listing은 학습용 production contract display이고 그날의 실행 selector set과 같지 않습니다.

오답 함정: 인쇄된 세 파일을 D6 selector 세 개로 세거나, selector 하나만 존재한다고 나머지 source를 삭제하면 안 됩니다.

범위 한계: display 여부는 실행 여부를 뜻하지 않고, selector 여부도 source authorship을 뜻하지 않습니다.

실제 기술 이름exact-selector versus displayed-source set separation

26. D6 SecurityStatusContractTest가 직접 증명하지 않는 write·CORS 범위는 무엇인가요?

답: 이 method는 401·403·400·200과 두 errorCode를 assert하지만 other GET·invalid POST 뒤 DB write count, 완전한 CORS/CSRF 정책은 assert하지 않습니다.

근거: test에는 status와 jsonPath assertion은 있지만 거절 후 account·business_tx count assertion이 없습니다. preflight·origin allowlist·credentialed request도 실행하지 않습니다.

오답 함정: D5의 특정 transfer write0을 D6 모든 rejection write0으로 옮기거나 D6 핵심 개념·본문에 CORS·CSRF가 언급된다는 이유로 browser-origin 보안 완료라고 쓰면 안 됩니다.

범위 한계: D6 claim은 anonymous/authenticated-invalid-owner matrix Green의 직접 assertion에 제한해야 합니다.

실제 기술 이름bounded status-contract proof without database or CORS exhaustiveness

27. D6 evidence와 마지막 cutoff를 어떻게 확인하나요?

답: evidence/w20/day-6-selector-gate.json의 fresh selector 결과와 evidence/w20/security-status.md의 날짜·report·native exit·신규 파일을 확인하고 p681에서 닫습니다.

근거: expected 형식은 EXACT_SELECTOR_GREEN selectors=1 classes>=1 tests>=1 failures=0 errors=0 skipped=0 native_exit=0입니다. source 상대경로 src/test/java/com/example/financialcore/security/SecurityStatusContractTest.java와 package도 일치해야 합니다.

오답 함정: 오래된 XML, test 0건, 반대 status, state file 조회만으로 Green을 세거나 p682 이후 내용을 끌어오면 안 됩니다.

범위 한계: 이 preview는 command를 실행하지 않았고 p682에서 시작하는 D7 및 그 이후 범위를 포함하지 않습니다.

실제 기술 이름fresh single-selector evidence gate with strict curriculum cutoff

28. modern 코드 인벤토리와 proof 표찰은 어떻게 읽나요?

답: display closure는 canonical 7개와 illustrative 2개입니다. canonical은 Red starter 2, provided test 3, Green solution reference 2이고 illustrative는 Q31·Q32입니다.

근거: aggregate vector 9/359/327/79/248/327/33/4는 teaching units / physical lines / nonblank lines / setup lines / mapping rows / translation rows / source chunks / source-local tests입니다. source-local test 4는 선언 수이고 이 audit의 실행 수는 0입니다.

오답 함정: 9개 display item을 learner-authored 9개로 세거나 source audit PASS를 Docker/Testcontainers Green, every denied audit proof로 바꾸면 안 됩니다.

범위 한계: byte·분류·display closure 뒤에도 learner runtime, authorship, 운영 의미는 fresh evidence와 HUMAN_SEMANTIC_REVIEW_REQUIRED가 필요합니다.

실제 기술 이름canonical-versus-illustrative provenance and proof-boundary accounting

source audit pass가 확인한 PDF package display closure와 확인하지 않은 integration learner authorship every denied audit를 나눈 도식
그림 한눈에: 7 canonical·2 illustrative·4 declared test와 0 executed test를 다른 칸에 놓고 검증되지 않은 claim을 밖에 남깁니다.