두 개의 함수
# core/llm/prompts/__init__.py
def _hash_prompt(text: str) -> str:
return hashlib.sha256(text.encode()).hexdigest()[:12]
# core/llm/prompts/axes.py
def _hash_axes(data) -> str:
return hashlib.sha256(
json.dumps(data, sort_keys=True).encode()
).hexdigest()[:12]12자리 hex = 48비트. 닫힌 prompt 집합에서 충돌 확률은 무시할 수 있습니다. 목표는 탐지이지 암호학적 보안이 아닙니다.
axes 해시는 YAML 파서 버전과 Python dict 순서에 걸쳐 JSON 직렬화가 결정적이도록 sort_keys=True를 사용합니다.
고정 엔트리
PROMPT_VERSIONS / _PINNED_HASHES (sorted) AGENTIC_SUFFIX 5630f3a61683 ANALYST_SPECIFIC 44136fa355b3 ANALYST_SYSTEM b800a57a4599 ANALYST_TOOLS_SUFFIX 36055d5618f4 ANALYST_USER 63711de6c099 COMMENTARY_SYSTEM 488d8916d958 COMMENTARY_USER 2024ac4eba69 CROSS_LLM_DUAL_VERIFY 602669128ae2 CROSS_LLM_RESCORE 163b08e97d66 CROSS_LLM_SYSTEM bf303f600fce EVALUATOR_AXES 44136fa355b3 EVALUATOR_SYSTEM 93ecabb14a72 EVALUATOR_USER ad832adfadf0 PROSPECT_EVALUATOR_AXES 44136fa355b3 ROUTER_SYSTEM c4220baeb6c0 SYNTHESIZER_SYSTEM 1cbe199613a1 SYNTHESIZER_TOOLS_SUFFIX 1fd89d3ece5a SYNTHESIZER_USER e0bb4afab940
두 dict 모두 동일한 key set을 가집니다.
verify_prompt_integrity
def verify_prompt_integrity(*, raise_on_drift: bool = False) -> list[str]:
drifted = []
for name, pinned in _PINNED_HASHES.items():
if computed[name] != pinned:
drifted.append(f"Prompt drift: {name} pin={pinned} now={computed[name]}")
if drifted and raise_on_drift:
raise RuntimeError(...)
return drifted이 함수는 tests/test_karpathy_prompt_hardening.py::TestPromptDriftDetection에서 raise_on_drift=False (리스트 반환, 비어 있어야 함) 와 raise_on_drift=True (예외가 발생하지 않아야 함) 양쪽 모드로 호출됩니다.
재핀(re-pin) 절차
의도적으로 prompt를 변경했을 때.
.md파일을 편집합니다 (예.analyst.md).- 새 해시를 계산합니다.
uv run python -c " from core.llm.prompts import PROMPT_VERSIONS as V import json print(json.dumps(dict(sorted(V.items())), indent=2)) "
_PINNED_HASHES의 해당 엔트리를 업데이트합니다.uv run pytest tests/test_karpathy_prompt_hardening.py를 실행합니다.- prompt 변경과 핀 업데이트를 한 커밋으로 함께 묶어 커밋합니다.
prompt 변경과 핀 업데이트를 두 커밋으로 나누면 git history에 CI 실패 상태의 커밋이 남게 됩니다. bisect 친화적인 커밋이라면 핀과 prompt가 같은 보폭으로 움직입니다.
왜 잠금장치인가
해시 잠금장치는 Karpathy의 P4 원칙을 GEODE 식으로 표현한 것입니다. 한 번 통과한 품질 게이트는 조용히 후퇴해서는 안 된다는 원칙. prompt 변경은 우연히도 쉽게 일어납니다. 병합 충돌 해결, 자동 포매터, IDE rename 등. 그리고 그 변경이 모델 동작에 미치는 영향을 미리 예측하기는 어렵습니다. 잠금장치는 모든 prompt 변경을 의식적인 단계를 거치도록 강제합니다.
잠금장치가 다루지 않는 것
.geode/skills/의 skill 본문은PROMPT_ASSEMBLED훅 페이로드로 관찰되지만 핀으로 고정되지는 않습니다. prompt 주입된 skill 변경은 CI 실패가 아닙니다.- 렌더링된 prompt (
.format()변수 치환 이후) 는 해싱되지 않습니다.hash_rendered_prompt()는 존재하지만 호출자가 없습니다. geode-prompt-evolution P2 #3 참조. - 디스크 무결성은 런타임에 재검증되지 않습니다. 해싱은 패키지 import 시점에만 일어납니다.