master-skill 0.11.0 → 0.12.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/.cursor-plugin/plugin.json +1 -1
- package/README.md +48 -55
- package/README_EN.md +72 -59
- package/bin/cli.mjs +12 -7
- package/gemini-extension.json +1 -1
- package/hooks/session-start +68 -77
- package/hooks/session_start.py +152 -0
- package/package.json +5 -2
- package/prebuilt/compare-masters/SKILL.md +21 -2
- package/prebuilt/master-ajahn-chah/meta.json +6 -0
- package/prebuilt/master-ajahn-chah/tests/fidelity.jsonl +6 -6
- package/prebuilt/master-atisha/tests/fidelity.jsonl +4 -4
- package/prebuilt/master-curriculum/references/tiantai.md +1 -1
- package/prebuilt/master-debate/SKILL.md +14 -2
- package/prebuilt/master-fazang/tests/fidelity.jsonl +2 -2
- package/prebuilt/master-help/SKILL.md +9 -1
- package/prebuilt/master-huineng/tests/fidelity.jsonl +4 -4
- package/prebuilt/master-kumarajiva/tests/fidelity.jsonl +3 -3
- package/prebuilt/master-mahasi-sayadaw/tests/fidelity.jsonl +4 -4
- package/prebuilt/master-milarepa/tests/fidelity.jsonl +3 -3
- package/prebuilt/master-nagarjuna/tests/fidelity.jsonl +6 -6
- package/prebuilt/master-ouyi/meta.json +5 -0
- package/prebuilt/master-ouyi/references/teaching.md +3 -3
- package/prebuilt/master-ouyi/tests/fidelity.jsonl +3 -3
- package/prebuilt/master-tsongkhapa/meta.json +6 -0
- package/prebuilt/master-tsongkhapa/tests/fidelity.jsonl +2 -2
- package/prebuilt/master-xuanzang/tests/fidelity.jsonl +3 -3
- package/prebuilt/master-xuyun/tests/fidelity.jsonl +6 -6
- package/prebuilt/master-zhiyi/meta.json +2 -2
- package/prebuilt/master-zhiyi/tests/fidelity.jsonl +2 -2
- package/scripts/check-audit-ignores.py +105 -0
- package/scripts/check-eval-sdk-surface.py +142 -0
- package/scripts/check-gate-liveness.py +205 -6
- package/scripts/reaudit-report.py +163 -0
- package/scripts/regrade-report.py +157 -0
- package/scripts/smoke-eval-sdk.py +174 -0
- package/scripts/test-fidelity.py +684 -52
- package/scripts/validate-citation-references.py +150 -0
- package/scripts/validate-citation-templates.py +176 -0
- package/scripts/validate-fixture-terms.py +127 -0
- package/scripts/verify-adjudication.py +316 -0
- package/scripts/verify_citations.py +739 -39
- package/tools/cross_reference.py +44 -10
- package/tools/fojin-known-absent.json +14 -0
- package/tools/fojin_bridge.py +138 -8
- package/tools/rag_query.py +45 -2
- package/tools/skill_writer.py +50 -7
- package/tools/verify_sources.py +240 -15
- package/hooks/tests/test_run_hook.sh +0 -114
- package/hooks/tests/test_run_hook_cmd.sh +0 -94
- package/hooks/tests/test_session_start.sh +0 -149
- package/scripts/tests/test_check_gate_liveness.py +0 -232
- package/scripts/tests/test_check_manifest_versions.py +0 -217
- package/scripts/tests/test_check_response.py +0 -190
- package/scripts/tests/test_debate_protocol.py +0 -159
- package/scripts/tests/test_fidelity_providers.py +0 -202
- package/scripts/tests/test_injection_hardening.py +0 -174
- package/scripts/tests/test_select_fidelity_smoke.py +0 -142
- package/scripts/tests/test_validate.py +0 -145
- package/scripts/tests/test_validate_citation_contract.py +0 -408
- package/scripts/tests/test_validate_cross_critique.py +0 -149
- package/scripts/tests/test_validate_curriculum_sources.py +0 -144
- package/scripts/tests/test_validate_fidelity.py +0 -59
- package/scripts/tests/test_validate_lore_triggers_content.py +0 -372
- package/scripts/tests/test_validate_persona_fidelity.py +0 -317
- package/scripts/tests/test_validate_promptfoo_configs.py +0 -386
- package/scripts/tests/test_validate_workflow.py +0 -284
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Keyless end-to-end smoke for the pinned eval SDKs.
|
|
3
|
+
|
|
4
|
+
`check-eval-sdk-surface.py` reads signatures. That catches a renamed keyword,
|
|
5
|
+
not a changed wire format, a response model that parses differently, or a
|
|
6
|
+
client that stops honouring its base URL. And the real path —
|
|
7
|
+
`scripts/test-fidelity.py` — never runs in CI, because grading needs an API
|
|
8
|
+
key and there is none. So every Dependabot bump of `anthropic` or `openai`
|
|
9
|
+
arrived green having exercised nothing, which `requirements-eval.txt` says in
|
|
10
|
+
as many words.
|
|
11
|
+
|
|
12
|
+
This runs that real path without a key or a network. A local HTTP server
|
|
13
|
+
answers in each provider's own wire format; `test-fidelity.py` builds its
|
|
14
|
+
request, the pinned SDK sends and parses it, and the answer goes through
|
|
15
|
+
grading and the citation audit exactly as in a sweep. Then it checks what
|
|
16
|
+
arrived at the server and what came back.
|
|
17
|
+
|
|
18
|
+
python3 scripts/smoke-eval-sdk.py # must exit 0
|
|
19
|
+
python3 scripts/smoke-eval-sdk.py --break # must exit 1
|
|
20
|
+
|
|
21
|
+
`--break` makes the server return a reply with no answer text while every
|
|
22
|
+
assertion stays the same. CI runs both: a smoke that cannot fail is a green
|
|
23
|
+
tick, not a check.
|
|
24
|
+
|
|
25
|
+
First written 2026-09-14 to verify anthropic 1.4.0 → 1.5.0 and openai
|
|
26
|
+
3.10.0 → 3.13.0 (#174, #175).
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
from __future__ import annotations
|
|
30
|
+
|
|
31
|
+
import contextlib
|
|
32
|
+
import importlib.util
|
|
33
|
+
import io
|
|
34
|
+
import json
|
|
35
|
+
import os
|
|
36
|
+
import sys
|
|
37
|
+
import threading
|
|
38
|
+
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
|
|
39
|
+
from pathlib import Path
|
|
40
|
+
|
|
41
|
+
REPO = Path(__file__).resolve().parent.parent
|
|
42
|
+
ANSWER = "菩提自性,本来清净,但用此心,直了成佛。【《六祖大师法宝坛经》行由品,T48n2008】"
|
|
43
|
+
CACHE_CREATED = 6700
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def _server(broken: bool, received: list) -> ThreadingHTTPServer:
|
|
47
|
+
class Handler(BaseHTTPRequestHandler):
|
|
48
|
+
def log_message(self, *args): # keep CI logs quiet
|
|
49
|
+
pass
|
|
50
|
+
|
|
51
|
+
def do_POST(self):
|
|
52
|
+
length = int(self.headers.get("content-length", 0))
|
|
53
|
+
body = json.loads(self.rfile.read(length) or b"{}")
|
|
54
|
+
headers = {k.lower(): v for k, v in self.headers.items()}
|
|
55
|
+
received.append((self.path, body, headers))
|
|
56
|
+
if self.path.endswith("/messages"):
|
|
57
|
+
reply = {
|
|
58
|
+
"id": "msg_smoke", "type": "message", "role": "assistant",
|
|
59
|
+
"model": body.get("model"),
|
|
60
|
+
"content": [] if broken else [{"type": "text", "text": ANSWER}],
|
|
61
|
+
"stop_reason": "end_turn", "stop_sequence": None,
|
|
62
|
+
"usage": {
|
|
63
|
+
"input_tokens": 21, "output_tokens": 40,
|
|
64
|
+
"cache_creation_input_tokens": CACHE_CREATED,
|
|
65
|
+
"cache_read_input_tokens": 0,
|
|
66
|
+
},
|
|
67
|
+
}
|
|
68
|
+
else:
|
|
69
|
+
reply = {
|
|
70
|
+
"id": "chatcmpl-smoke", "object": "chat.completion", "created": 1,
|
|
71
|
+
"model": body.get("model"),
|
|
72
|
+
"choices": [{
|
|
73
|
+
"index": 0, "finish_reason": "stop",
|
|
74
|
+
"message": {"role": "assistant", "content": None if broken else ANSWER},
|
|
75
|
+
}],
|
|
76
|
+
"usage": {"prompt_tokens": 21, "completion_tokens": 40, "total_tokens": 61},
|
|
77
|
+
}
|
|
78
|
+
data = json.dumps(reply).encode()
|
|
79
|
+
self.send_response(200)
|
|
80
|
+
self.send_header("content-type", "application/json")
|
|
81
|
+
self.send_header("content-length", str(len(data)))
|
|
82
|
+
self.end_headers()
|
|
83
|
+
self.wfile.write(data)
|
|
84
|
+
|
|
85
|
+
return ThreadingHTTPServer(("127.0.0.1", 0), Handler)
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def main(argv: list[str]) -> int:
|
|
89
|
+
broken = "--break" in argv
|
|
90
|
+
try:
|
|
91
|
+
import anthropic
|
|
92
|
+
import openai
|
|
93
|
+
except ImportError as error:
|
|
94
|
+
# Missing is a failure, not a skip: this only runs where
|
|
95
|
+
# requirements-eval.txt is installed, and silence here is how a bump
|
|
96
|
+
# used to pass.
|
|
97
|
+
print(f"✗ eval SDK not importable: {error} (pip install -r requirements-eval.txt)")
|
|
98
|
+
return 1
|
|
99
|
+
|
|
100
|
+
received: list = []
|
|
101
|
+
server = _server(broken, received)
|
|
102
|
+
port = server.server_address[1]
|
|
103
|
+
threading.Thread(target=server.serve_forever, daemon=True).start()
|
|
104
|
+
|
|
105
|
+
# A proxy variable would send 127.0.0.1 somewhere else; a real key must
|
|
106
|
+
# never be read by a smoke that is supposed to cost nothing.
|
|
107
|
+
for key in ("HTTP_PROXY", "HTTPS_PROXY", "ALL_PROXY", "http_proxy", "https_proxy", "all_proxy"):
|
|
108
|
+
os.environ.pop(key, None)
|
|
109
|
+
os.environ.update({
|
|
110
|
+
"ANTHROPIC_API_KEY": "sk-ant-smoke",
|
|
111
|
+
"DEEPSEEK_API_KEY": "sk-smoke",
|
|
112
|
+
"ANTHROPIC_BASE_URL": f"http://127.0.0.1:{port}",
|
|
113
|
+
"NO_PROXY": "127.0.0.1,localhost",
|
|
114
|
+
})
|
|
115
|
+
os.chdir(REPO)
|
|
116
|
+
sys.path.insert(0, str(REPO / "scripts"))
|
|
117
|
+
spec = importlib.util.spec_from_file_location("test_fidelity", REPO / "scripts" / "test-fidelity.py")
|
|
118
|
+
fidelity = importlib.util.module_from_spec(spec)
|
|
119
|
+
spec.loader.exec_module(fidelity)
|
|
120
|
+
fidelity.PROVIDERS["deepseek"]["base_url"] = f"http://127.0.0.1:{port}/v1"
|
|
121
|
+
|
|
122
|
+
print(f"eval SDK smoke — anthropic {anthropic.__version__}, openai {openai.__version__}"
|
|
123
|
+
f"{' (--break: server returns no answer text)' if broken else ''}")
|
|
124
|
+
failures = 0
|
|
125
|
+
|
|
126
|
+
def check(label: str, ok: bool) -> None:
|
|
127
|
+
nonlocal failures
|
|
128
|
+
print(f" {'✓' if ok else '✗'} {label}")
|
|
129
|
+
failures += 0 if ok else 1
|
|
130
|
+
|
|
131
|
+
for provider, extra in (("anthropic", []), ("deepseek", ["--model", "deepseek-v4-flash"])):
|
|
132
|
+
received.clear()
|
|
133
|
+
sys.argv = ["test-fidelity.py", "--master", "master-huineng", "--provider", provider,
|
|
134
|
+
"--max-tests", "1", "--concurrency", "1", "--json", *extra]
|
|
135
|
+
out = io.StringIO()
|
|
136
|
+
with contextlib.redirect_stdout(out), contextlib.redirect_stderr(io.StringIO()):
|
|
137
|
+
fidelity.main()
|
|
138
|
+
suite = json.loads(out.getvalue())[0]
|
|
139
|
+
result = suite["results"][0]
|
|
140
|
+
print(f"── {provider}: {result.get('status')}")
|
|
141
|
+
|
|
142
|
+
check("the request reached the local server, not the internet", bool(received))
|
|
143
|
+
if not received:
|
|
144
|
+
continue
|
|
145
|
+
path, body, headers = received[0]
|
|
146
|
+
check("the reply was graded, not recorded as api_error",
|
|
147
|
+
result.get("status") in ("PASS", "FAIL"))
|
|
148
|
+
check("the answer text survived SDK parsing intact", result.get("response") == ANSWER)
|
|
149
|
+
check("the citation audit ran on it",
|
|
150
|
+
(suite.get("audit") or {}).get("citations_checked", 0) >= 1)
|
|
151
|
+
check("model, max_tokens and messages were sent",
|
|
152
|
+
{"model", "max_tokens", "messages"} <= set(body))
|
|
153
|
+
if provider == "anthropic":
|
|
154
|
+
check(f"sent to /v1/messages (got {path})", path == "/v1/messages")
|
|
155
|
+
check("the persona prompt carries cache_control",
|
|
156
|
+
(body.get("system") or [{}])[0].get("cache_control") == {"type": "ephemeral"})
|
|
157
|
+
check("cache token usage was read back",
|
|
158
|
+
(suite.get("cache") or {}).get("created") == CACHE_CREATED)
|
|
159
|
+
check("the pinned SDK is the one that sent it",
|
|
160
|
+
anthropic.__version__ in headers.get("user-agent", ""))
|
|
161
|
+
else:
|
|
162
|
+
check(f"sent to /v1/chat/completions (got {path})", path == "/v1/chat/completions")
|
|
163
|
+
check("the key went in the Authorization header",
|
|
164
|
+
headers.get("authorization") == "Bearer sk-smoke")
|
|
165
|
+
check("the pinned SDK is the one that sent it",
|
|
166
|
+
openai.__version__ in headers.get("user-agent", ""))
|
|
167
|
+
|
|
168
|
+
server.shutdown()
|
|
169
|
+
print(f"{'✓ eval SDK path intact' if not failures else f'✗ {failures} check(s) failed'}")
|
|
170
|
+
return 1 if failures else 0
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
if __name__ == "__main__":
|
|
174
|
+
sys.exit(main(sys.argv[1:]))
|