범위개요 + D1–D6 · 월–토p607 W19 heading 아래 + p608–637 + p638 D6 최종 Gate 상단 체크 2개
정본 상태SOURCE AUDIT PASSPDF·package·display byte 폐쇄
실행 상태W19 D1–D6 INTEGRATION NOT_RUNtestsExecutedByAudit=0
이 이야기는 p607 W19 heading 아래 + p608–637 + p638 D6 최종 Gate 상단 체크 2개만 다룹니다. p607 상단의 W18 공식 참고는 제외하고, p638 하단 D7, p643 주간 통합, p644 공식 참고, p645 W20도 포함하지 않습니다. strict D1–D6 초회 예상시간은 7시간 50분–14시간 50분입니다. 공통 코어 · 트랙 선택 시 증권 기본이며 증권 주문·체결 전용 주차는 아닙니다. SOURCE AUDIT PASS는 PDF·package·display byte 폐쇄를 확인한 정적 판정일 뿐입니다. 현재 상태는 W19 D1–D6 INTEGRATION NOT_RUN이고, 이 preview의 파생 표지는 testsExecutedByAudit=0입니다. 원문 감사의 정확한 실행 경계는 No Docker/Testcontainers integration execution is claimed by this source audit; deterministic test and SQL oracles are read from pinned source/seed.이며 learner runtime Green이나 learner authorship을 주장하지 않습니다.
월요일 저녁, STARRY의 카드 보관함에서 가느다란 종이띠가 끝없이 흘러나왔다. 종이마다 X-Request-Id라고 적혀 있었지만 어떤 것은 비어 있었고, 어떤 것은 공백과 줄바꿈을 품고 있었다. 카운터 아래에서는 손님 계좌번호가 원문 그대로 찍힌 영수증까지 발견됐다. 히토리는 종이를 주워 들고 자신이 어제 처리한 요청이 다음 손님의 기록에 붙어 버린 것은 아닌지 걱정했다.
니지카는 새 기능부터 만들지 않았다. 먼저 reference와 learner 작업장을 서로 다른 절대경로로 나누고, 학습자가 직접 고칠 두 파일만 빈 무대에 올렸다. RequestIdFilter.java는 받은 header를 검증 없이 되돌려 주고 MDC를 쓰거나 정리하지 않는 starter였다. SensitiveDataMasker.java는 민감한 식별자를 그대로 반환했다. 둘은 고장 난 완성품이 아니라 일부러 빠진 동작을 드러내는 LEARNER_TARGET_STARTER였다.
그림 한눈에: 공식 장면컷은 니지카가 두 작업장과 source 역할을 확인하는 분위기용이며, 학습 사건·코드·수치는 원문 감사에 따른 비공식 구성입니다.그림 한눈에: ReferenceRoot의 제공 test와 LearnerRoot의 intentional starter 두 개를 분리하고, solution은 D3까지 닫아 둡니다.
키타가 starter 설치 표지에 초록 스티커를 붙이려 하자 료가 떼어 냈다. 예상 문구 W19 Starter; provided tests + intentionally incomplete targets installed는 설치와 ownership을 말할 뿐 기능 Green이 아니었다. evidence/w19/bridge-starter.json도 실제로 새로 실행해 만들어야 할 주 증거였다. 이 미리보기는 그 실행을 하지 않았고 source block 자체도 실행 명령이 아니었다.
“설치됐다는 말과 안전하다는 말 사이에 문 하나가 더 있어.” 니지카가 말했다. “오늘은 그 문에 이름을 붙인 거야.”
· · ·
둘째 날에는 세 장의 test 계약서가 무대에 펼쳐졌다. RequestIdFilterTest에는 유효한 req-w19-1이 response header·request attribute·filter 안 MDC에서 같고, chain이 끝난 뒤 MDC가 NULL이어야 한다는 test와 위험한 header가 36자 UUID로 교체돼야 한다는 test가 있었다. MaskingTest에는 긴 값·NULL·짧은 값·resource ID의 정확한 문자열 계약 두 개가 있었다. AuditPropagationIT에는 타인 계좌 조회가 403으로 끝난 뒤 같은 requestId를 가진 DENIED audit 한 행이 남는 test 하나가 있었다. 인쇄된 세 test source에는 모두 다섯 @Test가 있었지만, D2의 intentional Red target은 learner 파일 두 개뿐이었다.
그림 한눈에: 지정 assertion 두 개가 실패한 intentional Red와 import·compile 오류 같은 우연한 실패를 갈라 봅니다.
Red의 exact marker는 validRequestIdIsReturnedStoredForTheRequestAndRemovedFromMdc와 accountNumberKeepsAtMostTheLastFourCharacters였다. tests>0, 지정 marker 두 개, native_exit!=0이 함께 있어야 했다. 아무 compile 오류나 Red로 세면 test 계약을 읽었다는 증거가 되지 않았다. 반대로 AuditPropagationIT가 이 단계에서 통과하거나 실패한다는 사실만으로 학습자 구현의 저작권을 만들 수도 없었다. 그것은 PROVIDED_TEST_CONTRACT와 PROVIDED_FIXTURE_VERIFIED로 분리되는 제공 audit fixture의 경계였다.
D2의 전체 expected 문구는 W19 LearnerRed; native_exit!=0; exact markers=validRequestIdIsReturnedStoredForTheRequestAndRemovedFromMdc;accountNumberKeepsAtMostTheLastFourCharacters였다. 두 method 사이의 세미콜론까지 포함한 한 묶음이며, 문구를 읽는 것만으로 실제 Red evidence가 생기지는 않았다.
히토리는 실패가 빨간색이면 모두 같은 줄 알았다고 털어놓았다. 니지카는 “의도한 assertion까지 도착한 실패”와 “그 전에 넘어져 버린 실패”를 다른 상자에 넣었다. evidence/w19/bridge-recordred.json에 들어갈 expected marker는 지도였고, 지금 그 지도를 읽은 것과 실제 JUnit XML을 새로 만든 것은 구분했다.
· · ·
셋째 날, 네 사람은 드디어 두 starter를 직접 고치는 연습을 했다. 안전한 requestId는 [A-Za-z0-9._:-]{1,64}에 맞을 때만 그대로 썼다. 누락·공백·줄바꿈·길이초과 입력은 신뢰하지 않고 서버가 UUID를 새로 만들었다. 그 선택을 request attribute, response header, MDC 세 위치에 같은 값으로 넣고 chain이 정상 종료하든 예외로 끝나든 finally에서 MDC key를 제거하는 것이 목표였다.
그림 한눈에: 공식 장면컷은 네 사람이 안전한 입력과 교체할 입력, cleanup 경계를 토론하는 분위기용입니다.그림 한눈에: allowlist에 맞는 ID는 echo하고, 누락·공백·개행·길이초과 ID는 36자 UUID로 교체합니다.그림 한눈에: 하나의 requestId가 attribute·response·MDC로 흐르고 chain 뒤 finally에서 MDC가 제거됩니다.
료는 cleanup 상자 옆에 작은 경고를 붙였다. 현재 solution은 pre-existing MDC 값을 저장했다가 복원하지 않고 remove한다. 비동기 thread로 MDC가 자동 전파되는 것도 아니다. requestId는 사건을 연결하는 좌석표이지 인증 token이나 권한 판단 근거가 아니며, UUID regex가 uniqueness나 entropy까지 증명하지도 않는다.
masker는 NULL이나 blank를 *로, 123-456-7890을 **7890으로, 12를 12로, ACCOUNT/123456을 ACCOUNT:**3456으로 바꾸는 계약을 가졌다. 하지만 짧은 값은 별표 뒤에 원문 전체가 남는다. ASCII가 아닌 문자와 구두점을 제거하는 정규화 때문에 서로 다른 입력이 같은 표시값이 될 수 있고, resource type은 별도 검증 없이 prefix에 붙는다. 마스킹은 암호화·인가·credential rotation을 대신하지 않았다.
그림 한눈에: 네 exact masking 결과와 함께 짧은 값 노출·Unicode collision·resource type 미검증 경계를 표시합니다.
같은 날의 Q29는 “업무일 기준 전일 대비 거래액 차이”였다. shipped workbook 정본 답안은 없었다. 학습용 illustrative SQL은 모든 SUCCESS business_tx의 amount를 합치고 OPENING·REVERSAL도 포함한다는 가정을 먼저 적었다. business_date - 1의 전 달력일과 self join하므로 휴일을 건너뛰는 영업일 calendar가 아니다. 2026-07-01은 total 1500, previous 2129999, difference -2128499이고, 2026-12-29는 전날 SUCCESS 집계가 없어 previous와 difference가 NULL이다. 나머지는 2026-12-30 difference=1; 2026-12-31 difference=900000; 2027-01-01 difference=-999500; 2027-01-02 difference=700이며, 축약 exact difference는 2026-12-30=1, 12-31=900000, 2027-01-01=-999500, 01-02=700이다.
그림 한눈에: SUCCESS 일별 합계를 전 달력일과 self join하고, 전일 집계가 없으면 NULL로 남기는 Q29 가정을 봅니다.
니지카는 W19 LearnerSolutionVerified; exact target hashes=2라는 expected 문구도 실행 결과처럼 읽지 않았다. 학습자가 Red 뒤 두 파일을 직접 쓴 경로만 learner-authored가 될 수 있었다. solution을 복사하는 수동 복구 경로는 QA_OVERLAY/VerifiedGreen일 뿐이며 QA_OVERLAY ≠ learner-authored Green이었다. 어느 경로든 source hash와 실제 실행 증거, 사람의 의미 검토가 따로 필요했다.
· · ·
넷째 날에는 두 learner target과 제공 denied-audit fixture를 한 무대에서 연결하는 계획표가 나왔다. manifest의 Green selector는 RequestIdFilterTest, MaskingTest, AuditPropagationIT 세 개였다. 실제 RecordGreen이라면 각 class가 tests>0이고 failures·errors·skipped가 0인 새 JUnit XML과 native exit, source mode를 확인해야 했다.
그림 한눈에: selector 세 개의 실행 상태와 learner target 두 개·provided audit fixture 한 개의 ownership을 서로 다른 열로 봅니다.
“세 개가 함께 Green이면 세 개를 우리가 만든 건가요?” 키타가 물었다.
“실행 상태와 저작 상태는 다른 열이야.” 니지카가 답했다. “RequestIdFilter와 SensitiveDataMasker만 learner가 Red 뒤 직접 쓴 target이고, denied-audit 구현과 integration test는 provided fixture야. recovery가 QA overlay면 상태 이름도 VerifiedGreen으로 남겨야 하고.”
D4의 source-mode 분기까지 포함한 exact expected 문구는 W19 LearnerGreen for learner-typed path OR VerifiedGreen source_mode=QA_OVERLAY for recovery path였다. 앞 경로의 실행 성공을 뒤 경로의 learner authorship으로 옮겨 적을 수 없었다.
타인 계좌를 customer-2가 조회하면 응답은 403이고, audit-denied-1로 찾은 event는 정확히 한 행이어야 했다. actor는 customer-2, result는 DENIED, error는 ACCESS_DENIED, masked resource는 ACCOUNT:로 시작하지만 원래 식별자 전체와 같지 않아야 했다. 같은 requestId가 고객 응답과 audit row를 이어 주었다.
그림 한눈에: 권한 없는 GET은 403으로 끝나고 업무 transaction은 되돌아가지만, 같은 requestId의 가려진 DENIED audit 한 행은 별도 경계에 남습니다.
그러나 이 한 test는 success audit, exactly-once 전 경로, 보관 기간, tamper resistance, audit 저장 실패 때의 transaction 정책을 증명하지 않는다. masked 값이 원문과 다르다는 assertion도 모든 포맷을 고정하지 않는다. SOURCE AUDIT PASS가 이 integrated Gate를 실행했다는 뜻도 아니었다.
· · ·
다섯째 날에는 긴 계좌번호가 찍힌 카드와 짧은 두 자리 카드가 나란히 놓였다. 오늘 exact selector는 MaskingTest 하나였다. 실제 완료라면 EXACT_SELECTOR_GREEN selectors=1 classes>=1 tests>=1 failures=0 errors=0 skipped=0 native_exit=0과 새 evidence를 확인해야 하지만, 이 문서에서 그 명령을 실행하지 않았다.
그림 한눈에: 공식 장면컷은 카운터에서 공개해도 되는 표시값과 숨길 원문을 함께 점검하는 분위기용입니다.
secret scan과 credential rotation은 masker test와 다른 일이다. 오늘 새로 쓴 파일의 scan report가 깨끗하더라도 Git 과거 이력 전체가 깨끗하다고 말할 수 없고, 실제 credential 노출 가능성이 있으면 값을 가리는 대신 폐기하고 교체해야 했다. 계좌번호 마지막 네 글자가 남는 정책도 조직의 privacy 요구와 다시 맞춰야 했다.
Q30은 “계좌별 최근 성공 거래 1건”이었다. illustrative SQL은 account를 시작 table로 삼고 LEFT JOIN LATERAL을 써 성공 거래가 없는 계좌도 남겼다. direct business_tx.account_id만 보고 counterparty로 참여한 거래는 포함하지 않았다. SUCCESS라면 OPENING·REVERSAL도 포함했으며, 동률은 occurred_at DESC, tx_id DESC로 고정했다. oracle은 8개 account 행, account 101은 ...212, 103과 104는 NULL, 105는 ...210이었다. 나머지는 102→...102 amount 20000; 106→...106 amount499999; 107→...107 amount500000; 108→...108 amount1000000이며, 모두 SUCCESS OPENING이다. 같은 값을 축약 없이 묶으면 account 102 ...102 amount20000, 106 ...106 amount499999,107 ...107 amount500000,108 ...108 amount1000000 all SUCCESS OPENING이다.
그림 한눈에: account 한 행마다 LEFT LATERAL로 최근 SUCCESS 한 건을 고르고, 동률은 occurred_at·tx_id로 안정 정렬합니다.
Q29와 Q30 모두 학습용 예시 · 정본 답안 아님이었다. prompt가 고정하지 않은 status·tx_type·금액 부호·calendar·counterparty·0건 보존 정책을 주석으로 공개했기 때문에 유용한 예시일 뿐, learner가 제출해야 할 shipped canonical answer가 되지 않았다.
· · ·
여섯째 날의 마지막 상자에는 고객에게 보낼 오류 봉투와 내부 조사 기록이 나란히 들어 있었다. exact selector는 RequestIdFilterTest와 ApiExceptionHandlerTest 두 개였다. 유효 ID echo, 누락·invalid ID의 서버 생성, 다음 요청 MDC 누수 0, 외부 response에서 SQL·exception class·stack trace 원문 노출 0만 오늘의 claim이었다.
D6 실행 성공의 exact 형식은 EXACT_SELECTOR_GREEN selectors=2 classes>=1 tests>=1 failures=0 errors=0 skipped=0 native_exit=0이었다. 이것도 실제 새 JUnit XML과 evidence가 동반될 때만 관찰 결과가 된다.
그런데 PDF가 D6에 전문으로 보여 주는 source는 RequestIdFilterTest, AuditPropagationIT, MaskingTest 세 개였다. 실행 selector 두 개와 displayed source 세 개는 서로 같은 집합이 아니었다. selector인 ApiExceptionHandlerTest 전문은 인쇄되지 않았고, displayed source 중 audit와 masking test는 D6 exact selector가 아니었다. 숫자가 2와 3이라고 어느 쪽을 다른 쪽의 목록으로 바꾸면 안 됐다.
그림 한눈에: 고객 body에는 stable errorCode·message·requestId만 두고 SQL·exception·stack trace는 내부 경계 밖으로 내보내지 않습니다.
고객에게 보이는 requestId와 내부 진단이 같은 사건을 가리켜도 requestId는 인증 근거가 아니다. 외부 입력은 검증해야 하고, 안전하지 않은 값은 그대로 반사하지 않는다. 비노출 token scan 하나로 전체 log-injection 방어를 완료했다고 주장할 수도 없다. error body와 내부 log의 목적을 분리하고, test하지 않은 공격 벡터는 claim에서 제외했다.
p637의 D6 최종 Gate가 p638 상단으로 넘어가면서 마지막 두 체크가 이어졌다. 첫째, ApiError에 SQL·exception text가 노출되지 않는다. 둘째, 전체 log-injection 방어를 검증했다고 과장하지 않는다. 그 아래 일 모듈 | W19 감사·masking Gate부터는 D7이므로 니지카는 문을 닫았다.
· · ·
여섯 장의 계획표 아래 적힌 초회 예상시간을 더하면 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분이다. 막힘 중단선과 실제 소요시간은 별도로 기록하고, 예상보다 빨리 통과했다고 시간을 채우지 않는다.
현대 코드 뒤풀이의 display closure는 canonical 7개와 illustrative 2개다. canonical은 intentional Red starter 2개, test source 3개, Green solution 2개다. illustrative는 Q29·Q30 두 SQL이다. content aggregate vector 9/237/208/45/163/208/31/5는 차례로 teaching units 9개 / physical lines 237줄 / nonblank lines 208줄 / setup lines 45줄 / mapping rows 163개 / translation rows 208개 / source chunks 31개 / source-local tests 5개를 뜻한다. source-local @Test 5개는 source inventory이지 이 미리보기 감사가 실행한 test 수가 아니다. 전체 코드 문서의 source audit 범위는 W19 전체 p607–644라 strict preview subset과 다르고, 이 preview에서는 p644를 제외한다.
니지카는 마지막으로 세 표찰을 벽에 붙였다. SOURCE AUDIT PASS는 byte와 분류의 폐쇄, No Docker/Testcontainers integration execution is claimed by this source audit; deterministic test and SQL oracles are read from pinned source/seed.는 실행 claim 없음, HUMAN_SEMANTIC_REVIEW_REQUIRED는 ownership·업무 가정·보안 경계를 사람이 다시 판단해야 한다는 뜻이었다. 히토리는 초록색 펜을 내려놓고 대신 다음 실행에서 확인할 evidence path를 적었다.
종이띠는 더 이상 유령처럼 보이지 않았다. 안전한 추적표는 같은 요청의 세 위치를 이어 주고 끝나면 메모판에서 사라졌다. 수상한 표는 새 번호로 바뀌었다. 카드번호는 필요한 끝부분만 남았고, 거절된 행동은 원문을 가린 채 한 행으로 이어졌다. 무엇을 실행했고 누가 썼는지까지 정확히 구분하자 STARRY의 밤은 조용해졌다.
본편의 비유를 W19 requestId·masking·denied audit의 정확한 source 역할과 증거 경계로 다시 연결합니다. 모든 답은 p607 W19 heading 아래 + p608–637 + p638 D6 최종 Gate 상단 체크 2개에 한정합니다. 현재 상태는 W19 D1–D6 INTEGRATION NOT_RUN이고 이 preview의 파생 표지는 testsExecutedByAudit=0입니다. expected marker를 실제 Green으로 바꾸어 읽지 않습니다.
1. 이번 미리보기의 strict PDF 범위는 어디인가요?
답: p607에서 W19 heading 아래의 개요를 포함하고 p608–637 전체, p638 상단의 D6 최종 Gate 체크 두 개까지만 포함합니다.
근거: 정확한 범위 표기는 p607 W19 heading 아래 + p608–637 + p638 D6 최종 Gate 상단 체크 2개입니다. p607 상단 W18 공식 참고, p638 하단 D7, p643 주간 통합, p644 공식 참고, p645 W20은 제외합니다.
오답 함정: p607이나 p638이 혼합 페이지라는 사실을 무시하고 페이지 전체를 한 주차에 넣으면 W18 tail 또는 D7이 섞입니다.
범위 한계: modern 코드 문서의 source audit은 W19 전체 p607–644를 닫으므로 이 preview subset과 동일하지 않습니다.
실제 기술 이름mixed-page semantic boundary for W19 overview and D1–D6
2. D1–D6의 초회 예상시간 합계는 얼마인가요?
답: strict D1–D6 합계는 7시간 50분–14시간 50분, 즉 470–890분입니다.
오답 함정: p607 주간 전체 시간이나 D7 45–90분을 더해 D1–D6 시간이라고 부르면 범위가 달라집니다.
범위 한계: 예상시간은 active-time 계획값입니다. 실제 소요시간·막힘 중단선·24–72시간 재검증 시간과 같지 않습니다.
실제 기술 이름bounded active-time sum for six curriculum modules
3. SOURCE AUDIT PASS를 현재 Green이라고 말할 수 있나요?
답: 아니요. SOURCE AUDIT PASS는 PDF·package·display byte 폐쇄를 확인한 정적 결과이고 현재 상태는 W19 D1–D6 INTEGRATION NOT_RUN입니다.
근거: testsExecutedByAudit=0은 이 preview의 파생 표지입니다. source audit의 정확한 문구는 No Docker/Testcontainers integration execution is claimed by this source audit; deterministic test and SQL oracles are read from pinned source/seed.입니다. 공통 코어 · 트랙 선택 시 증권 기본이라는 트랙 표기도 실행 상태를 바꾸지 않습니다.
오답 함정: source hash가 맞거나 expected stdout이 문서에 있다는 이유만으로 learner runtime Green 또는 learner authorship을 주장하면 안 됩니다.
범위 한계: 실제 Green은 learner workspace에서 새 JUnit XML·native exit·source hash·evidence를 다시 확인해야 합니다.
실제 기술 이름byte-verified source closure versus unexecuted runtime evidence
4. D1의 두 starter는 왜 일부러 불완전한가요?
답: learner가 test 계약의 Red를 보고 직접 복구할 target과 제공된 source의 ownership을 분리하기 위해서입니다.
근거: RequestIdFilter starter는 header를 검증 없이 반사하고 MDC lifecycle이 없으며, SensitiveDataMasker starter는 raw 식별자를 그대로 반환합니다.
오답 함정: starter 설치 marker를 기능 완료나 secure implementation으로 읽으면 intentional Red의 목적이 사라집니다.
범위 한계: starter source block은 그 자체로 실행 결과가 아니고, D3 전 solution을 복사해서도 learner-authored 증거가 되지 않습니다.
실제 기술 이름intentional Red starter with learner-owned production targets
그림 한눈에: 제공 test가 있는 ReferenceRoot와 학습자가 고칠 starter 두 개가 있는 LearnerRoot를 분리합니다.
5. ReferenceRoot와 LearnerRoot를 왜 다른 절대경로로 두나요?
답: 정본 reference를 읽는 작업과 learner가 직접 입력한 결과를 파일·hash·ownership 수준에서 구분하기 위해서입니다.
근거: D1 Gate는 두 root가 다른지, 두 starter가 learner 상대경로에 설치됐는지, 제공 test와 target ownership이 evidence에 기록됐는지를 봅니다.
오답 함정: 같은 폴더를 두 변수에 넣으면 reference 복사와 learner 작성이 구분되지 않고 target hash도 저작 증거가 될 수 없습니다.
범위 한계: 경로가 다르다는 사실만으로 learner가 source를 직접 썼거나 기능이 Green이라는 뜻은 아닙니다.
실제 기술 이름reference-versus-learner workspace isolation
6. bridge-starter.json은 무엇을 증명하나요?
답: 실제 D1 실행에서 제공 test와 intentional starter 두 target의 설치·hash·ownership을 기록하는 주 evidence입니다.
오답 함정: counterparty_account_id 참여를 포함하거나 INNER LATERAL로 0건 account를 지우거나 timestamp만 정렬하면 결과 계약이 달라집니다.
범위 한계: SUCCESS의 OPENING·REVERSAL 포함과 0건 account 보존은 prompt가 고정하지 않아 예시가 공개한 가정입니다.
실제 기술 이름per-account latest-row LEFT LATERAL with total order
그림 한눈에: 계좌를 보존한 채 최신 SUCCESS 한 건을 고르고 동률은 tx_id로 끊습니다.
24. Q29·Q30을 정본 답안이라고 부르면 안 되는 이유는 무엇인가요?
답: workbook에 shipped canonical answer가 없고 두 SQL은 pinned schema·seed와 명시한 가정으로 만든 illustrative 자료이기 때문입니다.
근거: 두 파일 모두 canonicalAnswerShipped=false이며 status·tx_type·calendar·counterparty·zero-row 정책의 prompt gap을 주석으로 공개합니다.
오답 함정: oracle 숫자가 맞는다는 이유로 업무 요구사항 전체가 확정됐거나 learner 제출 정답이라고 부르면 안 됩니다.
범위 한계: 실제 과제에서는 requirement owner가 정책을 정하고 learner가 자기 SQL과 실행 결과를 evidence로 남겨야 합니다.
실제 기술 이름noncanonical illustrative SQL with explicit assumptions
25. D6에서 실제로 실행하도록 지정된 exact selector 두 개는 무엇인가요?
답: RequestIdFilterTest와 ApiExceptionHandlerTest 두 개입니다.
근거: D6 contract는 valid ID echo, missing/invalid ID server generation, MDC cleanup, 외부 body의 SQL·stack·exception text 노출 0을 확인합니다. exact 성공 형식은 EXACT_SELECTOR_GREEN selectors=2 classes>=1 tests>=1 failures=0 errors=0 skipped=0 native_exit=0입니다.
오답 함정: D4의 세-selector 목록을 그대로 D6에 재사용하거나 MaskingTest를 D6 exact selector에 넣으면 원문 명세와 달라집니다.
범위 한계: 두 selector Green만으로 전체 log injection, 모든 exception mapping, async context propagation을 증명하지 않습니다.
실제 기술 이름two-selector request-correlation and ApiError regression
26. D6 selector 2개와 displayed source 3개는 왜 서로 다르나요?
답: selector는 RequestIdFilterTest·ApiExceptionHandlerTest지만 PDF가 D6에 전문으로 보여 주는 source는 RequestIdFilterTest·AuditPropagationIT·MaskingTest 세 개입니다.
근거: ApiExceptionHandlerTest는 selector dependency인데 full source listing이 없고, displayed audit·masking test는 D6 selector가 아닙니다.
오답 함정: “2개 selector”와 “3개 displayed source”를 같은 집합의 다른 표현으로 읽으면 실제 실행 대상과 인쇄 source가 뒤바뀝니다.
범위 한계: source가 인쇄되지 않았다는 사실은 test가 없다는 뜻이 아니며, 반대로 source가 인쇄됐다고 D6에서 실행됐다는 뜻도 아닙니다.
실제 기술 이름selector-to-displayed-source set mismatch
그림 한눈에: 실행 selector와 인쇄 source를 구분하면서 외부 ApiError의 공개 필드와 내부 진단 경계를 봅니다.
27. ApiError에 공개할 값과 숨길 값은 무엇인가요?
답: 외부 body에는 stable errorCode·message·requestId만 공개하고 SQL text·exception class/message·stack trace 같은 내부 정보는 노출하지 않습니다.
근거: p638 상단 D6 최종 Gate는 ApiError의 SQL·exception text 비노출과 전체 log-injection 방어를 검증했다고 과장하지 않았는지 확인합니다.
오답 함정: 디버깅을 쉽게 하려고 내부 exception 원문을 고객 body에 넣거나 token scan 하나를 전체 방어 proof로 부르면 안 됩니다.
범위 한계: 고객 body 비노출과 내부 log encoding·retention·access control은 서로 다른 보안 책임입니다.
실제 기술 이름stable public error envelope and information-disclosure boundary
근거: source-local @Test 5개는 인쇄 source inventory이고 실행 수는 0입니다. SOURCE AUDIT PASS, No Docker/Testcontainers integration execution is claimed by this source audit; deterministic test and SQL oracles are read from pinned source/seed., HUMAN_SEMANTIC_REVIEW_REQUIRED를 함께 읽어야 합니다.
오답 함정: 9개 display item을 learner-authored 9개로 세거나 static HTML QA를 Docker/Testcontainers integration Green으로 바꾸면 안 됩니다.
범위 한계: source audit은 byte·분류·display closure를 보증하지만 현재 learner workspace의 실행·authorship·업무 의미는 새 evidence와 사람 검토가 필요합니다.
실제 기술 이름canonical-versus-illustrative provenance with semantic review boundary