pipeline: 원장 검사기를 문서 계약에 맞추고 터미널 증거 회귀를 잇는다

R2 — `stage-contracts.md` 「관문 요약」이 정본인데 `STAGES` 가 넷을 빠뜨리고 있었다.
S4 `preview-figure.py` · S5 `check_evidence.mjs` · S6 `check_body.mjs`·`check_evidence.mjs` ·
S7 `build-tech-log-tree.py` 를 더한다.

그리고 `style_profile.mjs` 는 관문이 아니라 측정이다 — 문서 계약이 「error 0」을 붙인 것은
`check_prose` 뿐이다(`stage-contracts.md:178`·`:252`). 그런데 원장 검사기가 exit≠0 을 전부
error 로 세어서, 정직하게 exit 1 로 적은 원장은 무조건 실패하고 0 으로 고쳐 적으면 그건
지어낸 것이 된다. `MEASUREMENT_GATES` 로 갈라 **돌았다는 것만 요구하고 종료 코드 0 은
요구하지 않는다.** 대신 `exit` 칸이 없으면 error 다 — 안 돌리고 넘어가는 것을 막는다.
곁증명(`_side_proof`)에도 같은 규칙을 넣는다.

대조군 셋으로 확인했다.
  preview-figure 를 뺀 원장          → FAIL 「관문이 빠졌다」
  style_profile 을 exit 1 로 적은 원장 → PASS
  style_profile 의 exit 칸을 지운 원장 → FAIL 「측정 관문의 종료 코드가 없다」

이 변경으로 `runs/virtualization/2026-09-08-1958/run.json` 이 빨개진다. S6 에서
`check_evidence.mjs` 를 실제로 안 돌린 원장이라 맞는 결과다. 낮춰서 초록으로 만들지 않는다.

R10 — `scripts/terminal-evidence/tests/` 가 문서에 적힌
`unittest discover -s scripts/tests` 범위 밖이고, 직접 `discover` 를 걸면 `render_terminal`
import 경로가 `sys.path` 에 없어 깨진다. 회귀가 초록인데 아무도 안 부르는 상태였다.
`scripts/tests/test_terminal_evidence.py` 가 `load_tests` 로 경로를 얹고 끌어온다 (86 → 92).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wp9jNbePAmWc5jQwCYhK9v
This commit is contained in:
DongHyeonka
2026-09-10 11:06:59 +09:00
co-authored by Claude Opus 5
parent 43e1aadef0
commit c2742a66cc
2 changed files with 73 additions and 6 deletions
+42
View File
@@ -0,0 +1,42 @@
"""`scripts/terminal-evidence/tests/` 를 문서에 적힌 한 명령이 함께 돌게 잇는다.
`python3 -m unittest discover -s scripts/tests` 는 그 폴더만 훑는다. 터미널 증거 렌더러의
테스트는 `scripts/terminal-evidence/tests/` 에 따로 있어서 그 명령에 안 잡혔고,
`verify-pipeline.py` 도 unittest 를 부르지 않는다. 그래서 **초록인데 아무도 안 부르는 회귀**가 됐다.
`discover -s scripts/terminal-evidence/tests` 를 직접 돌려도 깨진다 — 그 테스트가
`render_terminal` 을 같은 폴더 기준으로 부르는데 그 경로가 `sys.path` 에 없다. 여기서
경로를 얹고 파일을 직접 불러 `load_tests` 로 끌어온다. 중첩 `discover` 는 쓰지 않는다 —
`top_level_dir` 이 바깥을 가리키면 unittest 가 거절한다.
"""
from __future__ import annotations
import importlib.util
import os
import sys
import unittest
_HERE = os.path.dirname(os.path.abspath(__file__))
_TE = os.path.join(os.path.dirname(_HERE), "terminal-evidence")
_TE_TESTS = os.path.join(_TE, "tests")
def load_tests(loader: unittest.TestLoader, tests: unittest.TestSuite,
pattern: str | None) -> unittest.TestSuite:
if not os.path.isdir(_TE_TESTS):
return tests
if _TE not in sys.path:
sys.path.insert(0, _TE)
for name in sorted(os.listdir(_TE_TESTS)):
if not (name.startswith("test") and name.endswith(".py")):
continue
mod_name = "terminal_evidence_" + name[:-3]
spec = importlib.util.spec_from_file_location(
mod_name, os.path.join(_TE_TESTS, name))
if spec is None or spec.loader is None:
continue
module = importlib.util.module_from_spec(spec)
sys.modules[mod_name] = module
spec.loader.exec_module(module)
tests.addTests(loader.loadTestsFromModule(module))
return tests