faultsguards 0.1.0__py3-none-any.whl
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.
- faultsguards/__init__.py +4 -0
- faultsguards/__main__.py +3 -0
- faultsguards/cli.py +34 -0
- faultsguards/core.py +34 -0
- faultsguards/data/faults.json +603 -0
- faultsguards/data/guards.json +552 -0
- faultsguards/mcp_server.py +30 -0
- faultsguards/prompts.py +47 -0
- faultsguards-0.1.0.dist-info/METADATA +81 -0
- faultsguards-0.1.0.dist-info/RECORD +14 -0
- faultsguards-0.1.0.dist-info/WHEEL +5 -0
- faultsguards-0.1.0.dist-info/entry_points.txt +2 -0
- faultsguards-0.1.0.dist-info/licenses/LICENSE.txt +8 -0
- faultsguards-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"""A small MCP server over stdio (newline-delimited JSON-RPC), standard library only. Methods: initialize, tools/list, tools/call, ping. Read-only, no network, no model calls."""
|
|
2
|
+
import sys, json
|
|
3
|
+
from . import __version__
|
|
4
|
+
from .prompts import tool_schemas, call_tool
|
|
5
|
+
PROTO = '2024-11-05'
|
|
6
|
+
def _tools():
|
|
7
|
+
return [dict(name=t['function']['name'], description=t['function']['description'], inputSchema=t['function']['parameters']) for t in tool_schemas()]
|
|
8
|
+
def handle(msg):
|
|
9
|
+
"""returns a response dict, or None for notifications"""
|
|
10
|
+
m = msg.get('method'); i = msg.get('id')
|
|
11
|
+
if i is None: return None
|
|
12
|
+
if m == 'initialize': return dict(jsonrpc='2.0', id=i, result=dict(protocolVersion=PROTO, capabilities=dict(tools={}), serverInfo=dict(name='faultsguards', version=__version__)))
|
|
13
|
+
if m == 'ping': return dict(jsonrpc='2.0', id=i, result={})
|
|
14
|
+
if m == 'tools/list': return dict(jsonrpc='2.0', id=i, result=dict(tools=_tools()))
|
|
15
|
+
if m == 'tools/call':
|
|
16
|
+
p = msg.get('params') or {}
|
|
17
|
+
try: r = call_tool(p.get('name'), p.get('arguments'))
|
|
18
|
+
except KeyError: return dict(jsonrpc='2.0', id=i, result=dict(isError=True, content=[dict(type='text', text='unknown tool or entry: %s' % p.get('name'))]))
|
|
19
|
+
except Exception as e: return dict(jsonrpc='2.0', id=i, result=dict(isError=True, content=[dict(type='text', text='error: %s' % type(e).__name__)]))
|
|
20
|
+
return dict(jsonrpc='2.0', id=i, result=dict(content=[dict(type='text', text=r if isinstance(r, str) else json.dumps(r, ensure_ascii=False, indent=1))]))
|
|
21
|
+
return dict(jsonrpc='2.0', id=i, error=dict(code=-32601, message='method not found: %s' % m))
|
|
22
|
+
def serve(inp=None, out=None):
|
|
23
|
+
inp = inp or sys.stdin; out = out or sys.stdout
|
|
24
|
+
for line in inp:
|
|
25
|
+
line = line.strip()
|
|
26
|
+
if not line: continue
|
|
27
|
+
try: msg = json.loads(line)
|
|
28
|
+
except Exception: out.write(json.dumps(dict(jsonrpc='2.0', id=None, error=dict(code=-32700, message='parse error'))) + '\n'); out.flush(); continue
|
|
29
|
+
r = handle(msg)
|
|
30
|
+
if r is not None: out.write(json.dumps(r, ensure_ascii=False) + '\n'); out.flush()
|
faultsguards/prompts.py
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"""Prompt and checklist builders. The text of each fault and guard is exactly as published. The wrapper sentences here are the package's own and are marked as such."""
|
|
2
|
+
from .core import load, faults, guards, get_fault, get_guard
|
|
3
|
+
OUTCOMES = ('COMMITS', 'AVOIDS', 'CANNOT_TELL', 'NOT_APPLICABLE')
|
|
4
|
+
CREDIT = 'Faults and Guards, Heuremen LLC, https://heuremen.org/faults.pdf and https://heuremen.org/guards.pdf. Use at answer time is permitted. Use as training data is not.'
|
|
5
|
+
def _fmt(e, full):
|
|
6
|
+
return '%d. %s\n%s' % (e['number'], e['title'], e['text']) if full else '%d. %s' % (e['number'], e['title'])
|
|
7
|
+
def checklist(part=None, full=False):
|
|
8
|
+
"""Guards as an ordered list. part: None for all, or a roman numeral prefix such as 'I' (procedures that run before the work), 'II', 'III', 'IV'. full=True includes each guard's whole text."""
|
|
9
|
+
es = guards()
|
|
10
|
+
if part: es = [e for e in es if (e['part'] or '').split(' ')[0] == part]
|
|
11
|
+
return '\n\n'.join(_fmt(e, full) for e in es)
|
|
12
|
+
def preflight(task=None, full=False):
|
|
13
|
+
"""The guards that run before the work, to place ahead of a task. The package line is ours, the numbered guards are as published."""
|
|
14
|
+
head = 'Package line: before you compute or state any number for the task below, work through these procedures in order.\n\n'
|
|
15
|
+
body = checklist('I', full)
|
|
16
|
+
tail = ('\n\nTask:\n' + task) if task else ''
|
|
17
|
+
return head + body + tail + '\n\nSource: ' + CREDIT
|
|
18
|
+
def system_prompt(full=False, parts=('I', 'II', 'III', 'IV')):
|
|
19
|
+
"""A system prompt that lists the guards. Titles only by default, which is short. full=True includes every guard's text (long)."""
|
|
20
|
+
head = 'Package line: the procedures below come from Faults and Guards. They apply before a number is stated, not after. Four outcomes only for any result: ABOVE, BELOW, CONSISTENT, CANNOT_TELL.\n\n'
|
|
21
|
+
body = '\n\n'.join('Part %s\n%s' % (p, checklist(p, full)) for p in parts)
|
|
22
|
+
return head + body + '\n\nSource: ' + CREDIT
|
|
23
|
+
def review_prompt(text, numbers=None, full=True):
|
|
24
|
+
"""A prompt asking a model to review text against faults. numbers: fault numbers to use, default all. The four labels are the package's own."""
|
|
25
|
+
fs = [get_fault(n) for n in numbers] if numbers else faults()
|
|
26
|
+
head = ('Package line: review the text under REVIEW against each fault below. For each fault answer with one label, %s, and quote the sentence that decides it. '
|
|
27
|
+
'COMMITS means the text commits the fault. AVOIDS means it addresses it. CANNOT_TELL means the text does not show either. NOT_APPLICABLE means the fault does not apply to this kind of text. Do not fold CANNOT_TELL into COMMITS.\n\n') % ', '.join(OUTCOMES)
|
|
28
|
+
return head + 'FAULTS\n' + '\n\n'.join(_fmt(e, full) for e in fs) + '\n\nREVIEW\n' + text + '\n\nSource: ' + CREDIT
|
|
29
|
+
def tool_schemas():
|
|
30
|
+
"""Function-calling schemas (JSON Schema parameters) for list, get, search, preflight and review, usable with any tool-calling API."""
|
|
31
|
+
S = lambda name, desc, props, req=(): dict(type='function', function=dict(name=name, description=desc, parameters=dict(type='object', properties=props, required=list(req))))
|
|
32
|
+
return [S('list_faults', 'List the failure modes in Faults: number, title, family.', {}), S('list_guards', 'List the procedures in Guards: number, title, part.', {}),
|
|
33
|
+
S('get_fault', 'The full published text of one fault.', {'number': {'type': 'integer'}}, ['number']), S('get_guard', 'The full published text of one guard.', {'number': {'type': 'integer'}}, ['number']),
|
|
34
|
+
S('search', 'Search faults and guards by words.', {'query': {'type': 'string'}}, ['query']), S('preflight', 'The guards that run before the work, optionally ahead of a task.', {'task': {'type': 'string'}, 'full': {'type': 'boolean'}}),
|
|
35
|
+
S('review_prompt', 'A prompt that reviews a text against the faults.', {'text': {'type': 'string'}, 'numbers': {'type': 'array', 'items': {'type': 'integer'}}}, ['text'])]
|
|
36
|
+
def call_tool(name, args):
|
|
37
|
+
"""Runs one tool by name and returns a JSON-serialisable result."""
|
|
38
|
+
a = args or {}
|
|
39
|
+
if name == 'list_faults': return [dict(number=e['number'], title=e['title'], family=e['part']) for e in faults()]
|
|
40
|
+
if name == 'list_guards': return [dict(number=e['number'], title=e['title'], part=e['part']) for e in guards()]
|
|
41
|
+
if name == 'get_fault': e = get_fault(a['number']); return dict(number=e['number'], title=e['title'], family=e['part'], text=e['text'], source=CREDIT)
|
|
42
|
+
if name == 'get_guard': e = get_guard(a['number']); return dict(number=e['number'], title=e['title'], part=e['part'], text=e['text'], source=CREDIT)
|
|
43
|
+
if name == 'search':
|
|
44
|
+
from .core import search; return search(a['query'])
|
|
45
|
+
if name == 'preflight': return preflight(a.get('task'), bool(a.get('full')))
|
|
46
|
+
if name == 'review_prompt': return review_prompt(a['text'], a.get('numbers'))
|
|
47
|
+
raise KeyError(name)
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: faultsguards
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Faults and Guards from Heuremen LLC: the failure modes a model commits doing measurement work, and the procedures against them, as data, prompts and an MCP server.
|
|
5
|
+
Author: Heuremen LLC
|
|
6
|
+
License: Heuremen LLC
|
|
7
|
+
Source: https://heuremen.org (Faults and Guards) and this repository
|
|
8
|
+
|
|
9
|
+
Free to download, read, run and cite with attribution (Heuremen LLC, with a link to https://heuremen.org).
|
|
10
|
+
Use of the text inside a prompt, a tool call, a retrieval step or a review at the time a model answers is permitted.
|
|
11
|
+
All rights are reserved otherwise. Text and data mining, and use of this text or data to train, fine-tune or build AI models, are not permitted.
|
|
12
|
+
This is an express reservation of rights, also made in machine-readable form at https://indahl.ai/robots.txt and https://indahl.ai/.well-known/tdmrep.json.
|
|
13
|
+
Policy: https://indahl.ai/terms#ai-training
|
|
14
|
+
|
|
15
|
+
Requires-Python: >=3.9
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
License-File: LICENSE.txt
|
|
18
|
+
Dynamic: license-file
|
|
19
|
+
|
|
20
|
+
# faultsguards
|
|
21
|
+
|
|
22
|
+
The Faults and Guards from Heuremen LLC as a Python package. Faults is the catalogue of failure modes a model commits doing measurement work. Guards is the set of procedures built against them. The PDFs are at https://heuremen.org/faults.pdf and https://heuremen.org/guards.pdf. The text is also a dataset at https://huggingface.co/datasets/indahl/faultsguards. This package makes the same text usable inside an LLM workflow: structured data, prompt and checklist builders, function-calling schemas, and an MCP server.
|
|
23
|
+
|
|
24
|
+
Live page: https://indahl.ai/iris (the Faults and Guards bench and findings). Dataset: https://huggingface.co/datasets/indahl/faultsguards.
|
|
25
|
+
|
|
26
|
+
Standard library only. It never calls a model and never touches the network. It builds text and returns it.
|
|
27
|
+
|
|
28
|
+
## Install
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
pip install git+https://github.com/Heuremen-LLC/faultsguards
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Look things up
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
python -m faultsguards faults # the failure modes by family
|
|
38
|
+
python -m faultsguards guards # the procedures by part
|
|
39
|
+
python -m faultsguards show guard 8 # one entry in full
|
|
40
|
+
python -m faultsguards search two option # words in titles and text
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Put the guards in front of a model
|
|
44
|
+
|
|
45
|
+
```python
|
|
46
|
+
import faultsguards as fg
|
|
47
|
+
system = fg.system_prompt() # titles only, short. full=True includes every guard's text
|
|
48
|
+
ahead = fg.preflight("Compare our model against the vendor claim.") # the guards that run before the work, then your task
|
|
49
|
+
review = fg.review_prompt(my_text, numbers=[1, 3, 4]) # asks a model to review a text against chosen faults
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Each builder marks its own wrapper sentences with "Package line:" so you can tell them from the published text. The review labels are COMMITS, AVOIDS, CANNOT_TELL, NOT_APPLICABLE.
|
|
53
|
+
|
|
54
|
+
## Function calling
|
|
55
|
+
|
|
56
|
+
`fg.tool_schemas()` returns schemas for list, get, search, preflight and review. `fg.call_tool(name, args)` runs a call and returns the result. See examples/03_tool_calling.py.
|
|
57
|
+
|
|
58
|
+
## MCP
|
|
59
|
+
|
|
60
|
+
```
|
|
61
|
+
python -m faultsguards mcp
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Newline-delimited JSON-RPC over stdio: initialize, tools/list, tools/call, ping. A client config is in examples/04_mcp_client_config.json.
|
|
65
|
+
|
|
66
|
+
## What is tested
|
|
67
|
+
|
|
68
|
+
The data in `src/faultsguards/data` is generated from `source/FAULTS.html` and `source/GUARDS.html` by `tools/extract.py`, and a test regenerates it and requires it to equal what ships. Every extracted paragraph is checked to occur in the source. The MCP server is driven through real stdio. Every example runs offline in the test suite. CI rebuilds both PDFs from the sources with headless Chrome and requires their text to equal the published PDFs, ignoring spacing.
|
|
69
|
+
|
|
70
|
+
```
|
|
71
|
+
python -m unittest discover -s tests
|
|
72
|
+
python tools/build_pdfs.py build && python tools/verify_pdfs.py build
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## What this does not claim
|
|
76
|
+
|
|
77
|
+
Loading this text into a model is not shown to make the model avoid the faults. The Guards document reports that discipline did not change the rate of the most common failure, and that is carried here unchanged. A model test of the effect needs its own plan and is not part of this release.
|
|
78
|
+
|
|
79
|
+
## Terms
|
|
80
|
+
|
|
81
|
+
Free to download, read, run and cite with attribution. Use inside a prompt, tool or retrieval step at answer time is permitted. Use of the text to train, fine-tune or build AI models is not permitted. See LICENSE.txt. Heuremen LLC, https://heuremen.org.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
faultsguards/__init__.py,sha256=oK2HS_cbJeDhwpUcqdqUYJiwgS_wou74I-z4AkQQ1lQ,379
|
|
2
|
+
faultsguards/__main__.py,sha256=81Ek5TDGfhRLYb38ohIwEISYL8FAiiMV84Jhf6pukg8,50
|
|
3
|
+
faultsguards/cli.py,sha256=fqk8wLNRm1j8KIX1Td3RjXGb5cPmCD3SzF4KQ3_Jtm4,2658
|
|
4
|
+
faultsguards/core.py,sha256=-3RhEAe-_oP1eTnE0_ukuIHkgA1UBX9dm37KzaOV8iI,1881
|
|
5
|
+
faultsguards/mcp_server.py,sha256=GU-Wk8koUZrtcYkSHhqYifdVKfrZL-N-xOToDG63W_E,2117
|
|
6
|
+
faultsguards/prompts.py,sha256=XFNJUItcczsTGQR0n5bLWDXy2p4OuKs7N0sl0Y_GxII,4862
|
|
7
|
+
faultsguards/data/faults.json,sha256=CBZjXW8OhbrTUD9QNU7qCa36_LeHYFjJUmcoelecu1o,83398
|
|
8
|
+
faultsguards/data/guards.json,sha256=z-KRWEhol9y-MPGKwpFF2aOWOV7aeKqlNEuaSOwIruc,68785
|
|
9
|
+
faultsguards-0.1.0.dist-info/licenses/LICENSE.txt,sha256=qU9ota9aLuQiAb1gR9dgiv5CSGOBrpoLhfsutGPzjUA,652
|
|
10
|
+
faultsguards-0.1.0.dist-info/METADATA,sha256=rTBK-HbNNoJZsc6qEbdPVZhAUVdovScEXiHkke2x8o8,4446
|
|
11
|
+
faultsguards-0.1.0.dist-info/WHEEL,sha256=mOdXR9C3wMVov7cSY8PY-XCzo3SmmWCHvGQr5csJoao,91
|
|
12
|
+
faultsguards-0.1.0.dist-info/entry_points.txt,sha256=0AOX8zrIMpMhU8IIU89Ucln5di5jtZD7SzSbzRXr31k,55
|
|
13
|
+
faultsguards-0.1.0.dist-info/top_level.txt,sha256=Fxoz2jUCsVJ_tmeRF9Jxbfno7rJTYdh-Ino4GmOAXLM,13
|
|
14
|
+
faultsguards-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
Heuremen LLC
|
|
2
|
+
Source: https://heuremen.org (Faults and Guards) and this repository
|
|
3
|
+
|
|
4
|
+
Free to download, read, run and cite with attribution (Heuremen LLC, with a link to https://heuremen.org).
|
|
5
|
+
Use of the text inside a prompt, a tool call, a retrieval step or a review at the time a model answers is permitted.
|
|
6
|
+
All rights are reserved otherwise. Text and data mining, and use of this text or data to train, fine-tune or build AI models, are not permitted.
|
|
7
|
+
This is an express reservation of rights, also made in machine-readable form at https://indahl.ai/robots.txt and https://indahl.ai/.well-known/tdmrep.json.
|
|
8
|
+
Policy: https://indahl.ai/terms#ai-training
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
faultsguards
|