G7 선행 조건 발견 — 공개 런타임에 admin/voice-runtime 이 없다
실측으로 찾았다. 공개 런타임은 119 paths 구버전이고 /admin/voice-runtime 이 배포돼 있지 않다. capture-g7-runtime-evidence.py 는 정확히 그 경로만 부르므로 artifact 2 를 만들 수 없다. 즉 마이크와 사람을 다 준비해도 오늘 실행하면 50분을 버리고 실패한다. 현재 소스에는 있다(admin.py:1699, 프리뷰 126 paths). 오케스트레이터가 시작 전에 이걸 검사하고 admin_voice_runtime_not_deployed 로 즉시 멈춘다. 공개 런타임 대상 --rehearse 가 exit 2 로 몇 초 만에 차단됐다. 판정 방식을 한 번 고쳤다. 처음엔 미인증 404/401 상태로 짰는데, Cloudflare 앞단이 자동화 클라이언트에게 존재하지 않는 경로까지 포함해 모든 경로를 403(error code 1010)으로 돌려주는 것을 확인했다. 그 신호로는 "배포 누락"과 "edge 차단"을 구분할 수 없어 작동하는 것처럼 보이지만 무의미한 검사였다. OpenAPI spec 의 paths 만 authoritative 하게 쓰도록 바꾸고 그 이유를 테스트로 남겼다. G7 실행 순서가 이렇게 확정된다. 1. current source 를 공개 런타임에 승격(비-secure origin crypto.randomUUID 수정 포함) 2. --rehearse 로 배관 확인 3. 동의 하 물리 마이크 50분 + human pack 으로 실제 실행 검증: 오케스트레이터 25/25, SSOT FAIL 0, dashboard E2E 10/10, ruff clean.
This commit is contained in:
parent
f3491be63f
commit
b866a48b01
5 changed files with 153 additions and 5 deletions
|
|
@ -70,6 +70,7 @@ class HostAlignmentTest(unittest.TestCase):
|
|||
args(admin_runtime_url="https://elsewhere.test/admin/voice-runtime",
|
||||
microphone_device="mic", confirm_physical_capture=True),
|
||||
Path("out"),
|
||||
admin_probe=lambda origin: ["/admin/voice-runtime"],
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -146,7 +147,8 @@ class LegCompositionTest(unittest.TestCase):
|
|||
|
||||
def test_all_three_legs_share_one_window_length(self) -> None:
|
||||
legs = MODULE.plan_legs(
|
||||
args(rehearse=True, duration_seconds=3_000.0), Path("out")
|
||||
args(rehearse=True, duration_seconds=3_000.0), Path("out"),
|
||||
admin_probe=lambda origin: ["/admin/voice-runtime"],
|
||||
)
|
||||
self.assertEqual([leg.name for leg in legs][1:], ["runtime", "topology"])
|
||||
for leg in legs[1:]:
|
||||
|
|
@ -163,7 +165,7 @@ class WindowExecutionTest(unittest.TestCase):
|
|||
started.append(argv[3])
|
||||
return FakeCompleted(0)
|
||||
|
||||
legs = MODULE.plan_legs(args(rehearse=True), Path("out"))
|
||||
legs = MODULE.plan_legs(args(rehearse=True), Path("out"), admin_probe=lambda origin: ["/admin/voice-runtime"])
|
||||
results = MODULE.run_window(legs, timeout=60, runner=runner)
|
||||
self.assertEqual(len(started), 3)
|
||||
self.assertTrue(all(result.ok for result in results))
|
||||
|
|
@ -172,13 +174,63 @@ class WindowExecutionTest(unittest.TestCase):
|
|||
def runner(argv, **kwargs):
|
||||
return FakeCompleted(1 if "capture-g7-runtime-evidence.py" in argv[3] else 0)
|
||||
|
||||
legs = MODULE.plan_legs(args(rehearse=True), Path("out"))
|
||||
legs = MODULE.plan_legs(args(rehearse=True), Path("out"), admin_probe=lambda origin: ["/admin/voice-runtime"])
|
||||
results = MODULE.run_window(legs, timeout=60, runner=runner)
|
||||
self.assertEqual(len(results), 3)
|
||||
failed = [r.name for r in results if not r.ok]
|
||||
self.assertEqual(failed, ["runtime"])
|
||||
|
||||
|
||||
class AdminEndpointPreflightTest(unittest.TestCase):
|
||||
"""공개 런타임이 구버전이라 endpoint 가 없으면 50분을 버리기 전에 막는다."""
|
||||
|
||||
ADMIN_URL = "https://api.example.test/admin/voice-runtime"
|
||||
|
||||
def test_missing_endpoint_is_rejected_before_the_window_starts(self) -> None:
|
||||
with self.assertRaises(MODULE.WindowError) as ctx:
|
||||
MODULE.assert_admin_endpoint_deployed(
|
||||
self.ADMIN_URL, paths_probe=lambda origin: ["/health", "/voice/speech"]
|
||||
)
|
||||
self.assertEqual(str(ctx.exception), "admin_voice_runtime_not_deployed")
|
||||
|
||||
def test_deployed_endpoint_is_accepted(self) -> None:
|
||||
origin = MODULE.assert_admin_endpoint_deployed(
|
||||
self.ADMIN_URL,
|
||||
paths_probe=lambda origin: ["/health", "/admin/voice-runtime"],
|
||||
)
|
||||
self.assertEqual(origin, "https://api.example.test")
|
||||
|
||||
def test_unauthenticated_status_is_never_used_as_the_signal(self) -> None:
|
||||
"""Cloudflare 는 자동화 클라이언트에 모든 경로를 403 으로 준다.
|
||||
|
||||
상태 코드로 판정하면 배포 누락을 통과시킨다. spec 만 본다.
|
||||
"""
|
||||
|
||||
probed: list[str] = []
|
||||
|
||||
def probe(origin: str):
|
||||
probed.append(origin)
|
||||
return ["/admin/voice-runtime"]
|
||||
|
||||
MODULE.assert_admin_endpoint_deployed(self.ADMIN_URL, paths_probe=probe)
|
||||
self.assertEqual(probed, ["https://api.example.test"])
|
||||
|
||||
def test_wrong_admin_url_path_fails_closed(self) -> None:
|
||||
with self.assertRaises(MODULE.WindowError) as ctx:
|
||||
MODULE.assert_admin_endpoint_deployed(
|
||||
"https://api.example.test/admin/something-else",
|
||||
paths_probe=lambda origin: ["/admin/voice-runtime"],
|
||||
)
|
||||
self.assertEqual(str(ctx.exception), "admin_runtime_url_unexpected_path")
|
||||
|
||||
def test_plan_refuses_a_deployment_without_the_endpoint(self) -> None:
|
||||
with self.assertRaises(MODULE.WindowError) as ctx:
|
||||
MODULE.plan_legs(
|
||||
args(rehearse=True), Path("out"), admin_probe=lambda origin: ["/health"]
|
||||
)
|
||||
self.assertEqual(str(ctx.exception), "admin_voice_runtime_not_deployed")
|
||||
|
||||
|
||||
class ReportTest(unittest.TestCase):
|
||||
def _results(self, codes=(0, 0, 0)):
|
||||
names = ("voice_soak", "runtime", "topology")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue