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.
@@ -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()
@@ -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,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (84.2.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ faultsguards = faultsguards.cli:main
@@ -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