spec-driven-docs 0.6.0

Spec-driven documentation: current specs, immutable decision records, and executable gates kept coherent for people and coding agents.
Documentation
import json, pathlib, subprocess, sys, tempfile
HERE = pathlib.Path(__file__).resolve().parent
HOOK = HERE / "lint_hook.py"

def run(event):
    r = subprocess.run([sys.executable, str(HOOK)], input=json.dumps(event), capture_output=True, text=True)
    return r.returncode, r.stdout, r.stderr

def test_post_tool_use_flags_a_slop_markdown_file():
    with tempfile.NamedTemporaryFile("w", suffix=".md", delete=False) as f:
        f.write("You should simply leverage the robust tool, making it seamless.\n"); path = f.name
    code, out, err = run({"hook_event_name": "PostToolUse", "tool_name": "Write", "tool_input": {"file_path": path}})
    assert code == 2 and "STE violations" in err, (code, err)

def test_post_tool_use_ignores_clean_file_and_non_markdown():
    with tempfile.NamedTemporaryFile("w", suffix=".md", delete=False) as f:
        f.write("Run the migration. Then restart the service.\n"); path = f.name
    assert run({"hook_event_name": "PostToolUse", "tool_input": {"file_path": path}})[0] == 0
    assert run({"hook_event_name": "PostToolUse", "tool_input": {"file_path": "/tmp/x.py"}})[0] == 0

def test_stop_flags_long_slop_reply_and_never_blocks():
    long = "Great question! " + "This is a robust sentence. " * 7 + "I hope this helps!"
    code, out, err = run({"hook_event_name": "Stop", "last_assistant_message": long})
    assert code == 0 and "systemMessage" in out, (code, out)
    msg = json.loads(out)["systemMessage"]
    assert "sentences" in msg and "opener" in msg and "closer" in msg and "slop" in msg, msg

def test_stop_is_silent_on_a_good_reply():
    code, out, err = run({"hook_event_name": "Stop", "last_assistant_message": "The build failed because the disk was full. Free 2 GB and run it again."})
    assert code == 0 and out.strip() == "", (code, out)

def test_garbage_stdin_exits_zero():
    r = subprocess.run([sys.executable, str(HOOK)], input="not json", capture_output=True, text=True)
    assert r.returncode == 0

if __name__ == "__main__":
    for name, fn in list(globals().items()):
        if name.startswith("test_"):
            fn(); print("ok", name)