Skip to content

test(e2e): 승인 후 아웃바운드 호출의 원본을 실물로 세워 차단 요인 FETCH-ORIGIN 을 닫는다 (차단 요인 1→0) - #139

Merged
dlddu-k3s-homelab-k3s-mcp[bot] merged 1 commit into
mainfrom
reconcile/rct_20260913-0003-opus-5-1m
Sep 14, 2026
Merged

dlddu-k3s-homelab-k3s-mcp[bot] merged 1 commit into
mainfrom
reconcile/rct_20260913-0003-opus-5-1m

Conversation

@dlddu-k3s-homelab-k3s-mcp

@dlddu-k3s-homelab-k3s-mcp dlddu-k3s-homelab-k3s-mcp Bot commented Sep 13, 2026

Copy link
Copy Markdown
Contributor

reconciler task rct_20260913-0003 · 모델 tbm_session-platform-e2e-mock-policy
(정합성 루프의 계획 단계가 스테이징한 PR — 머지는 사람 판단입니다)

gap — 규칙이 발화했고 트리거가 이 작업을 이름으로 지명했다

docs/test/e2e.md 「차단 요인」 원장의 마지막 한 행이 2026-09-13 재판정(#137)으로
선행: 없음소관: 이 모델 이 되어 착수 가능 0건 → 1건이 됐습니다. 이것이 정의
§「판정 규칙」 셋째 디스정션이고, scripts/check-fidelity-allowlist.py 가 부모 068e921
트리거 566c2ae 두 지점에서 독립으로 같은 값을 찍습니다(출력의 유일한 델타가 그 한 줄).
#137 자신이 fidelity:summary 에 「다음 감지가 착수 슬라이스를 연다」고 적어 이 작업을
지명합니다.

행이 해소 시 칸에 못박은 방향은 대역이 아니라 실물 배포입니다(판정: 없음) — 정적 문서를
내는 http 원본은 kind 에 그대로 세울 수 있으므로 정의의 EXT 배제 조항이 걸립니다
(deploy/minio.yaml · deploy/plugin-marketplace-git.yaml 선례). 이 PR 은 그 방향을 그대로
착수합니다.

무엇이 막고 있었나

승인이 떨어진 뒤의 실제 아웃바운드 GET 은 받아 줄 upstream 이 이 SUT 에 없어서 관측되지
않았습니다 — f3Prompt 의 대상이 클러스터에 실재하지 않는 https://example.test/doc 였고,
그래서 승인 갈래는 「게이트를 통과했다」는 데까지만 관측됐습니다.

오래 이 행을 세워 둔 벽은 「인클러스터 원본은 https 여야 하는데 MCP 컨테이너에 사설 발급자를
넣을 자리가 없다」였습니다. 그 벽은 전제와 함께 무너졌습니다 — #129
validateFetchTargethttp 를 함께 받게 되면서, 평문 http 원본에는 검증할 인증서가
애초에 없습니다.
같은 session-mcp 컨테이너가 평문 http 인클러스터 주소로 나가는 것도
가설이 아닙니다: 이 스위트가 매 실행 이미 하고 있습니다($APPROVAL_GATEWAY_URL =
http://approval-gateway-fake:8080).

변경

파일 무엇
deploy/fetch-origin.yaml (신규) 정적 문서를 내는 평문 http 원본(ConfigMap + Deployment + Service fetch-origin:8080). 이미지는 kind 에 이미 로드된 session-platform/data-plane:dev — 추가 빌드·pull 0. GET /doc[/키] · GET /access-log · GET /healthz
deploy/kustomization.yaml 오버레이에 엮는다(실물 묶음 쪽, 대역 묶음이 아니다)
scripts/e2e/up.sh 롤아웃 대기 추가 — 첫 승인 호출이 원본 리스너 기동과 경주하면 안 된다
control-plane/test/e2e_approval_gated_3_approval_path_test.go 대상 URL 교체 + 단언 둘
docs/test/e2e.md 차단 요인 행 삭제 · 집계 1→0 · §「남은 미검증 분기」 두 행 정리
docs/comment-policy/ledger.md + passes/2026-09-13-…md 15차 범위 재판정(21 → 61줄)
docs/doc-tracker.md 2026-09-07 인계 항목이 지시하던 EXT 등재는 일어나지 않았음을 기록

등재를 늘리지 않는다 — 그것이 이 방향의 핵심

원본은 승인된 모킹 예외가 아닙니다. 대신하는 것이 아무것도 없습니다 — 도구는 프로덕션 코드
그대로 http.DefaultClient 로 GET 하고, 원본은 그 GET 을 프로덕션 서버가 하는 일 그대로 받습니다.
호출 관찰도 치환을 들이지 않습니다: 원본 자신의 액세스 로그가 방문을 세고, /access-log
자기 자신과 /healthz 를 기록하지 않아 「결정 전 무도달」이 글자 그대로 0건이 됩니다.

그래서 불변식 1(seam 1:1)은 손대지 않습니다. 신규 파일에 스캔 토큰(test-only ·
E2E_* · mock-exception: · 인터셉트 호출)을 한 글자도 넣지 않아 as-is 지문이 바이트
불변
입니다:

seams=29 files=15
de1e68372a3576b45d72340088ed38d190a33c6b658ddbdb8bd17b240e8e1ec1   (변경 전후 동일)

단언 둘 — 표에서 소유 파일로 돌아온 것

  • 결정 전 무도달 — 요청이 PENDING 인 동안 원본 방문 0건. 원본이 실재하고 같은
    테스트가 뒤에서 도착을 관측
    하므로 더 이상 vacuous 하지 않습니다(그 도착이 이 음성 단언의
    대조군입니다).
  • 승인 후 GET 정확히 1회 — 승인 통지는 fetch 이전에 발행되므로 마커는 호출 완료의
    증거가 아닙니다. 도착까지 폴링하고(60s), 정착 창(5s) 뒤에 다시 재어 1이 유지되는지 봅니다.

대상 URL 은 세션별 경로 /doc/{세션ID} 로 키를 잡습니다 — 원본 하나가 클러스터 전체를 받으므로
「정확히 1회」는 호출자 범위에서만 의미가 있습니다(게이트웨이 대역의 externalId 와 같은 이유).
쿼리가 아니라 경로 세그먼트인 것은 URL 이 프롬프트를 타고 가기 때문입니다.

검증 (로컬 실측 — 전부 rc=0)

게이트 결과
python3 scripts/check-fidelity-allowlist.py OK — 등재 seam 7 · 회계 행 20 == 스캔 쌍 20 · 위반 0 · 인터셉트 7 · 차단 요인 0건 · 착수 가능 0건
python3 scripts/check_comment_policy.py OK — 판정 완료 3054줄 / 등재 범위 15
python3 scripts/check-render-fidelity.py OK (R1~R10)
./scripts/e2e/check-scenario-mapping.sh OK — 시나리오 37 = 매칭 0 + 예외 3 + 유예 34 + 공백 0
go vet ./... · go vet -tags=e2e ./... · gofmt -l . · go test ./... 전부 통과 (control-plane · data-plane)
kubectl kustomize deploy/ rc=0. 빌드 산출 diff 가 순수 추가(baseline 에서 사라진 줄 0)

두 단언 자체는 kind 실클러스터가 필요하므로 이 PR 의 e2e 워크플로가 처음 실행합니다
(deploy/** · control-plane/** · scripts/e2e/** 를 건드리므로 트리거됩니다).

범위 밖 — 원장 행의 지시에서 한 군데 갈립니다 (리뷰 포인트)

행은 §「남은 미검증 분기」의 두 행을 함께 지우라고 적었지만, 실측 결과 770 행은 두 절
담고 있고 그중 하나만 이 슬라이스가 삽니다.

그 응답이 같은 바이트열에 이어 붙음」은 못 삽니다 — 도구 결과를 되돌려 보내는 턴은
contenttool_result 뿐이라 대역의 lastUserText 가 빈 문자열을 내고, 지시어를 찾지
못한 대역은 프롬프트와 무관한 상수 한 줄로 답합니다(deploy/e2e-anthropic-fake.yaml
replyShape). 본문이 버퍼에 닿을 나머지 한 길은 CLI 가 도구 결과를 스크롤백에 렌더링하는
것인데, 그것은 이 SUT 가 정하지 않습니다.

그래서 771 행은 지우고, 770 행은 그 잔여 절만 남겨 재작성했습니다. 막힌 이유를 upstream
부재가 아니라 대역의 표현력으로 다시 적었고(§ 서두 (5) — claude-code-workload.md#시나리오 5
와 같은 벽), 그 형태는 원장이 아니라 그 표에 사는 것이 맞습니다(동결 후 정상 응답 행 선례).
차단 요인 원장 행은 그 원인이 실제로 사라지므로 예고대로 지웠습니다.

리터럴 http.DefaultClient.Do(req) 는 코드에 그대로 남습니다 — 행이 사라지므로 원장의 대조
대상이 함께 없어지는 것이지 코드를 고치는 작업이 아닙니다.

자매 PR 과의 충돌 (실측)

대상 결과
#130 (scenario-e2e rct_20260912-0005) 충돌 없음 — 양방향 git merge --no-commit --no-ff rc=0
#127 (AC-F5 후반) 충돌 2파일docs/test/e2e.md · docs/comment-policy/ledger.md

#127 충돌은 둘 다 기계적입니다:

⚠️ 귀속: main(99c2166) <- #127 단독 병합은 rc=0 · 충돌 0 입니다 — 즉 위 2파일은 이
PR 이 새로 만드는 충돌 표면이지 기존 충돌이 아닙니다(교집합이 아니라 대조군 병합으로 갈랐습니다).
둘 다 성질상 피할 수 없습니다: 같은 표의 다른 행을 지우고, 같은 합계 마커를 움직입니다.
나중에 착지하는 쪽이 위 둘을 해소하면 됩니다. docs/doc-tracker.md#127다른 hunk
충돌하지 않으며, 변경 이력 표 행은 #127 과 같은 자리를 다투므로 의도적으로 추가하지
않았습니다
.

롤백

되돌리기는 이 커밋 하나의 revert 입니다. 프로덕션 base(k8s/)는 한 줄도 바뀌지 않았고, 변경은
전부 e2e 오버레이(deploy/) · e2e 스위트 · 문서입니다. 원본 배포는 다른 리소스에 붙지 않는
독립 Deployment/Service 라 회수해도 기존 세션 경로에 영향이 없습니다.

…인 1→0)

`docs/test/e2e.md` 「차단 요인」 원장의 마지막 한 행이 2026-09-13 재판정(#137)으로
`선행: 없음` + `소관: 이 모델` 이 되어 착수 가능해졌다. 그 행이 스스로 못박은 해소 방향
(대역이 아니라 **실물 배포**, 정의의 EXT 배제 조항)을 그대로 착수한다.

**무엇이 막고 있었나.** 승인이 떨어진 뒤의 실제 아웃바운드 GET 은 그 호출을 받아 줄
upstream 이 이 SUT 에 없어서 관측되지 않았다 — `f3Prompt` 의 대상이 클러스터에 실재하지 않는
`https://example.test/doc` 였고, 그래서 승인 갈래는 「게이트를 통과했다」는 데까지만 관측됐다.
오래 이 행을 세워 둔 벽은 「인클러스터 원본은 https 여야 하는데 MCP 컨테이너에 사설 발급자를
넣을 자리가 없다」였는데, #129 로 `validateFetchTarget` 이 `http` 를 함께 받게 되면서 끊겼다 —
평문 http 원본에는 **검증할 인증서가 애초에 없다**.

**등재를 늘리지 않는다.** `deploy/fetch-origin.yaml` 은 승인된 모킹 예외가 아니라 실물 배포다
(`deploy/minio.yaml` · `deploy/plugin-marketplace-git.yaml` 과 같은 자리). 대신하는 것이
아무것도 없고 — 도구는 프로덕션 코드 그대로 `http.DefaultClient` 로 GET 한다 — 호출 관찰도
치환을 들이지 않는다: **원본 자신의 액세스 로그**가 방문을 세고, `/access-log` 는 자기 자신과
`/healthz` 를 기록하지 않아 「결정 전 무도달」이 글자 그대로 0건이 된다. seam 지문은 바이트
불변이다(`seams=29 files=15 · de1e6837…`) — 새 파일에 스캔 토큰을 한 글자도 넣지 않았다.

**단언 둘이 표에서 소유 파일로 돌아왔다.**
- **결정 전 무도달** — 요청이 `PENDING` 인 동안 원본 방문 0건. 원본이 실재하고 같은 테스트가
  뒤에서 도착을 관측하므로 더 이상 vacuous 하지 않다.
- **승인 후 GET 정확히 1회** — 승인 통지는 fetch **이전**에 발행되므로 마커는 호출 완료의
  증거가 아니다. 도착까지 폴링하고, 정착 창 뒤에 다시 재어 1이 유지되는지 본다.

대상 URL 은 세션별 경로(`/doc/{세션ID}`)로 키를 잡는다 — 원본 하나가 클러스터 전체를 받으므로
「정확히 1회」는 호출자 범위에서만 의미가 있다(게이트웨이 대역의 `externalId` 와 같은 이유).
쿼리가 아니라 경로 세그먼트인 것은 URL 이 프롬프트를 타고 가기 때문이다.

**범위 밖 — 원장 행의 지시에서 한 군데 갈린다.** 행은 §「남은 미검증 분기」의 **두 행**을 함께
지우라고 적었지만, 770 행이 담은 것은 두 절이고 그중 하나만 이 슬라이스가 산다. 「그 응답이
같은 바이트열에 이어 붙음」은 **못 산다** — 도구 결과를 되돌려 보내는 턴은 `content` 가
`tool_result` 뿐이라 대역의 `lastUserText` 가 빈 문자열을 내고, 대역은 프롬프트와 무관한 상수
한 줄로 답한다(`replyShape`). 본문이 버퍼에 닿을 나머지 한 길은 CLI 의 렌더링인데 그것은 이
SUT 가 정하지 않는다. 그래서 771 행은 지우고 **770 행은 그 잔여 절만 남겨 재작성**했다 —
막힌 이유는 upstream 부재가 아니라 **대역의 표현력**이라(§ 서두 (5), `시나리오 5` 와 같은 벽)
원장이 아니라 그 표에 사는 형태다.

집계: 차단 요인 **1 → 0** · 착수 가능 **1 → 0**. 등재 seam 7 · 회계 행 20 · 위반 0 ·
인터셉트 7 은 **불변**.

reconciler: rct_20260913-0003 (tbm_session-platform-e2e-mock-policy)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants