Introduce tools/quick_gate.py: a one-second check that parses every file in protocol, tests and tools, imports each protocol module, and runs the functional tests of the labs that need no experiment data. Wire it to a PostToolUse hook so edits under protocol or tests are checked automatically, and add two read-only review agents with slash commands that drive them: verifier for independent re-derivation of results, adversary for unsafe-state hunting in control, failsafe, session and reset code. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
60 lines
1.7 KiB
Python
60 lines
1.7 KiB
Python
"""
|
||
Обёртка быстрого шлюза для хука PostToolUse.
|
||
|
||
Читает JSON события со стандартного ввода. Если правка затронула файл Python
|
||
в protocol или tests, запускает tools/quick_gate.py.
|
||
|
||
Коды возврата:
|
||
0 — правка не по теме либо шлюз пройден, вывода нет;
|
||
2 — шлюз не пройден, текст ошибки уходит в stderr и возвращается модели.
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
import json
|
||
import os
|
||
from pathlib import Path
|
||
import re
|
||
import subprocess
|
||
import sys
|
||
|
||
PROJECT_ROOT = Path(__file__).resolve().parents[2]
|
||
WATCHED = re.compile(r"[\\/](?:protocol|tests)[\\/][^\\/]+\.py$")
|
||
|
||
|
||
def main() -> int:
|
||
try:
|
||
event = json.load(sys.stdin)
|
||
except (json.JSONDecodeError, ValueError):
|
||
return 0
|
||
|
||
tool_input = event.get("tool_input") or {}
|
||
tool_response = event.get("tool_response") or {}
|
||
file_path = tool_response.get("filePath") or tool_input.get("file_path") or ""
|
||
|
||
if not WATCHED.search(str(file_path)):
|
||
return 0
|
||
|
||
environment = dict(os.environ, PYTHONIOENCODING="utf-8")
|
||
|
||
completed = subprocess.run(
|
||
[sys.executable, str(PROJECT_ROOT / "tools" / "quick_gate.py")],
|
||
cwd=PROJECT_ROOT,
|
||
capture_output=True,
|
||
text=True,
|
||
encoding="utf-8",
|
||
errors="replace",
|
||
env=environment,
|
||
)
|
||
|
||
if completed.returncode == 0:
|
||
return 0
|
||
|
||
output = (completed.stdout + completed.stderr).strip()
|
||
print(output, file=sys.stderr)
|
||
return 2
|
||
|
||
|
||
if __name__ == "__main__":
|
||
raise SystemExit(main())
|