test(e2e): 승인 후 아웃바운드 호출의 원본을 실물로 세워 차단 요인 FETCH-ORIGIN 을 닫는다 (차단 요인 1→0) - #139
Merged
dlddu-k3s-homelab-k3s-mcp[bot] merged 1 commit intoSep 14, 2026
Merged
Conversation
…인 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)
This was referenced Sep 13, 2026
dlddu-k3s-homelab-k3s-mcp
Bot
deleted the
reconcile/rct_20260913-0003-opus-5-1m
branch
September 14, 2026 11:59
This was referenced Sep 14, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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 로
validateFetchTarget이http를 함께 받게 되면서, 평문 http 원본에는 검증할 인증서가애초에 없습니다. 같은
session-mcp컨테이너가 평문 http 인클러스터 주소로 나가는 것도가설이 아닙니다: 이 스위트가 매 실행 이미 하고 있습니다(
$APPROVAL_GATEWAY_URL=http://approval-gateway-fake:8080).변경
deploy/fetch-origin.yaml(신규)fetch-origin:8080). 이미지는 kind 에 이미 로드된session-platform/data-plane:dev— 추가 빌드·pull 0.GET /doc[/키]·GET /access-log·GET /healthzdeploy/kustomization.yamlscripts/e2e/up.shcontrol-plane/test/e2e_approval_gated_3_approval_path_test.godocs/test/e2e.mddocs/comment-policy/ledger.md+passes/2026-09-13-…mddocs/doc-tracker.mdEXT등재는 일어나지 않았음을 기록등재를 늘리지 않는다 — 그것이 이 방향의 핵심
원본은 승인된 모킹 예외가 아닙니다. 대신하는 것이 아무것도 없습니다 — 도구는 프로덕션 코드
그대로
http.DefaultClient로 GET 하고, 원본은 그 GET 을 프로덕션 서버가 하는 일 그대로 받습니다.호출 관찰도 치환을 들이지 않습니다: 원본 자신의 액세스 로그가 방문을 세고,
/access-log는자기 자신과
/healthz를 기록하지 않아 「결정 전 무도달」이 글자 그대로 0건이 됩니다.그래서 불변식 1(seam 1:1)은 손대지 않습니다. 신규 파일에 스캔 토큰(
test-only·E2E_*·mock-exception:· 인터셉트 호출)을 한 글자도 넣지 않아 as-is 지문이 바이트불변입니다:
단언 둘 — 표에서 소유 파일로 돌아온 것
PENDING인 동안 원본 방문 0건. 원본이 실재하고 같은테스트가 뒤에서 도착을 관측하므로 더 이상 vacuous 하지 않습니다(그 도착이 이 음성 단언의
대조군입니다).
증거가 아닙니다. 도착까지 폴링하고(60s), 정착 창(5s) 뒤에 다시 재어 1이 유지되는지 봅니다.
대상 URL 은 세션별 경로
/doc/{세션ID}로 키를 잡습니다 — 원본 하나가 클러스터 전체를 받으므로「정확히 1회」는 호출자 범위에서만 의미가 있습니다(게이트웨이 대역의
externalId와 같은 이유).쿼리가 아니라 경로 세그먼트인 것은 URL 이 프롬프트를 타고 가기 때문입니다.
검증 (로컬 실측 — 전부 rc=0)
python3 scripts/check-fidelity-allowlist.pypython3 scripts/check_comment_policy.pypython3 scripts/check-render-fidelity.py./scripts/e2e/check-scenario-mapping.shgo vet ./...·go vet -tags=e2e ./...·gofmt -l .·go test ./...kubectl kustomize deploy/두 단언 자체는 kind 실클러스터가 필요하므로 이 PR 의 e2e 워크플로가 처음 실행합니다
(
deploy/**·control-plane/**·scripts/e2e/**를 건드리므로 트리거됩니다).범위 밖 — 원장 행의 지시에서 한 군데 갈립니다 (리뷰 포인트)
행은 §「남은 미검증 분기」의 두 행을 함께 지우라고 적었지만, 실측 결과 770 행은 두 절을
담고 있고 그중 하나만 이 슬라이스가 삽니다.
「그 응답이 같은 바이트열에 이어 붙음」은 못 삽니다 — 도구 결과를 되돌려 보내는 턴은
content가tool_result뿐이라 대역의lastUserText가 빈 문자열을 내고, 지시어를 찾지못한 대역은 프롬프트와 무관한 상수 한 줄로 답합니다(
deploy/e2e-anthropic-fake.yaml의replyShape). 본문이 버퍼에 닿을 나머지 한 길은 CLI 가 도구 결과를 스크롤백에 렌더링하는것인데, 그것은 이 SUT 가 정하지 않습니다.
그래서 771 행은 지우고, 770 행은 그 잔여 절만 남겨 재작성했습니다. 막힌 이유를 upstream
부재가 아니라 대역의 표현력으로 다시 적었고(§ 서두 (5) —
claude-code-workload.md#시나리오 5와 같은 벽), 그 형태는 원장이 아니라 그 표에 사는 것이 맞습니다(동결 후 정상 응답 행 선례).
차단 요인 원장 행은 그 원인이 실제로 사라지므로 예고대로 지웠습니다.
리터럴
http.DefaultClient.Do(req)는 코드에 그대로 남습니다 — 행이 사라지므로 원장의 대조대상이 함께 없어지는 것이지 코드를 고치는 작업이 아닙니다.
자매 PR 과의 충돌 (실측)
scenario-e2e rct_20260912-0005)git merge --no-commit --no-ffrc=0docs/test/e2e.md·docs/comment-policy/ledger.md#127 충돌은 둘 다 기계적입니다:
docs/test/e2e.md— 같은 표에서 서로 다른 행을 지웁니다(이쪽 770·771, feat(approval-gated): AC-F5 후반 — 공유 볼륨을 파일시스템 아카이브에 실어 동결·복원을 건너 나른다 #127 은 동결·복원두 행). 해소는 양쪽 삭제를 모두 취하는 것입니다.
docs/comment-policy/ledger.md—판정-합계마커 한 줄(이쪽 3054, feat(approval-gated): AC-F5 후반 — 공유 볼륨을 파일시스템 아카이브에 실어 동결·복원을 건너 나른다 #127 3051). 해소는두 증분을 합산하고
python3 scripts/check_comment_policy.py로 확인하는 것입니다.main(99c2166) <- #127단독 병합은 rc=0 · 충돌 0 입니다 — 즉 위 2파일은 이PR 이 새로 만드는 충돌 표면이지 기존 충돌이 아닙니다(교집합이 아니라 대조군 병합으로 갈랐습니다).
둘 다 성질상 피할 수 없습니다: 같은 표의 다른 행을 지우고, 같은 합계 마커를 움직입니다.
나중에 착지하는 쪽이 위 둘을 해소하면 됩니다.
docs/doc-tracker.md는 #127 과 다른 hunk 라충돌하지 않으며,
변경 이력표 행은 #127 과 같은 자리를 다투므로 의도적으로 추가하지않았습니다.
롤백
되돌리기는 이 커밋 하나의 revert 입니다. 프로덕션 base(
k8s/)는 한 줄도 바뀌지 않았고, 변경은전부 e2e 오버레이(
deploy/) · e2e 스위트 · 문서입니다. 원본 배포는 다른 리소스에 붙지 않는독립 Deployment/Service 라 회수해도 기존 세션 경로에 영향이 없습니다.