proof-engine-wiki 1.33.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.
- proof_engine_wiki/__init__.py +3 -0
- proof_engine_wiki/cli.py +101 -0
- proof_engine_wiki/ingest.py +138 -0
- proof_engine_wiki/lint.py +76 -0
- proof_engine_wiki/markers.py +90 -0
- proof_engine_wiki-1.33.0.dist-info/METADATA +83 -0
- proof_engine_wiki-1.33.0.dist-info/RECORD +11 -0
- proof_engine_wiki-1.33.0.dist-info/WHEEL +5 -0
- proof_engine_wiki-1.33.0.dist-info/entry_points.txt +2 -0
- proof_engine_wiki-1.33.0.dist-info/licenses/LICENSE +21 -0
- proof_engine_wiki-1.33.0.dist-info/top_level.txt +1 -0
proof_engine_wiki/cli.py
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
"""proof-engine-wiki CLI: ingest | lint."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import argparse
|
|
6
|
+
import dataclasses
|
|
7
|
+
import json
|
|
8
|
+
import sys
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
|
|
11
|
+
try:
|
|
12
|
+
from proof_engine_wiki import __version__
|
|
13
|
+
except ImportError:
|
|
14
|
+
__version__ = "0.1.0"
|
|
15
|
+
|
|
16
|
+
from proof_engine_wiki.ingest import ingest_page
|
|
17
|
+
from proof_engine_wiki.lint import lint_wiki
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def _cmd_ingest(args) -> int:
|
|
21
|
+
result = ingest_page(
|
|
22
|
+
Path(args.path),
|
|
23
|
+
registry_only=args.registry_only,
|
|
24
|
+
dry_run=args.dry_run,
|
|
25
|
+
model=args.model,
|
|
26
|
+
)
|
|
27
|
+
payload = {
|
|
28
|
+
"path": str(result.path),
|
|
29
|
+
"markers": len(result.markers),
|
|
30
|
+
"resolved_from_registry": result.resolved_from_registry,
|
|
31
|
+
"generated": result.generated,
|
|
32
|
+
"misses": result.misses,
|
|
33
|
+
"errors": result.errors,
|
|
34
|
+
}
|
|
35
|
+
if args.json:
|
|
36
|
+
sys.stdout.write(json.dumps(payload, indent=2 if args.pretty else None) + "\n")
|
|
37
|
+
else:
|
|
38
|
+
sys.stdout.write(
|
|
39
|
+
f"{result.path}: {len(result.markers)} markers, "
|
|
40
|
+
f"{result.resolved_from_registry} resolved, "
|
|
41
|
+
f"{result.generated} generated, "
|
|
42
|
+
f"{result.misses} misses\n"
|
|
43
|
+
)
|
|
44
|
+
return 0 if result.misses == 0 and not result.errors else 1
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def _cmd_lint(args) -> int:
|
|
48
|
+
findings = lint_wiki(Path(args.path), skip_network=args.skip_network)
|
|
49
|
+
payload = {
|
|
50
|
+
"path": str(args.path),
|
|
51
|
+
"findings": [
|
|
52
|
+
{
|
|
53
|
+
"path": str(f.path), "line": f.line,
|
|
54
|
+
"kind": f.kind, "message": f.message, "detail": f.detail,
|
|
55
|
+
}
|
|
56
|
+
for f in findings
|
|
57
|
+
],
|
|
58
|
+
}
|
|
59
|
+
if args.json:
|
|
60
|
+
sys.stdout.write(json.dumps(payload, indent=2 if args.pretty else None) + "\n")
|
|
61
|
+
else:
|
|
62
|
+
for f in findings:
|
|
63
|
+
sys.stdout.write(f"{f.path}:{f.line}: [{f.kind}] {f.message}\n")
|
|
64
|
+
if not findings:
|
|
65
|
+
sys.stdout.write("clean\n")
|
|
66
|
+
return 0 if not findings else 1
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def build_parser() -> argparse.ArgumentParser:
|
|
70
|
+
p = argparse.ArgumentParser(prog="proof-engine-wiki")
|
|
71
|
+
p.add_argument("--version", action="version", version=__version__)
|
|
72
|
+
sub = p.add_subparsers(dest="cmd", required=True)
|
|
73
|
+
|
|
74
|
+
ing = sub.add_parser("ingest", help="Extract {{prove:}} markers and resolve them.")
|
|
75
|
+
ing.add_argument("path")
|
|
76
|
+
ing.add_argument("--registry-only", action="store_true")
|
|
77
|
+
ing.add_argument("--dry-run", action="store_true")
|
|
78
|
+
ing.add_argument("--model", default="sonnet")
|
|
79
|
+
ing.add_argument("--json", action="store_true")
|
|
80
|
+
ing.add_argument("--pretty", action="store_true")
|
|
81
|
+
ing.set_defaults(func=_cmd_ingest)
|
|
82
|
+
|
|
83
|
+
lnt = sub.add_parser("lint", help="Scan a wiki for unresolved markers and stale proofs.")
|
|
84
|
+
lnt.add_argument("path")
|
|
85
|
+
lnt.add_argument("--skip-network", action="store_true",
|
|
86
|
+
help="Skip URL reachability checks.")
|
|
87
|
+
lnt.add_argument("--json", action="store_true")
|
|
88
|
+
lnt.add_argument("--pretty", action="store_true")
|
|
89
|
+
lnt.set_defaults(func=_cmd_lint)
|
|
90
|
+
|
|
91
|
+
return p
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def main(argv=None) -> int:
|
|
95
|
+
parser = build_parser()
|
|
96
|
+
args = parser.parse_args(argv)
|
|
97
|
+
return args.func(args)
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
if __name__ == "__main__":
|
|
101
|
+
raise SystemExit(main())
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
"""Ingest: extract {{prove:}} markers, resolve or commission, rewrite page."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import subprocess
|
|
6
|
+
import sys
|
|
7
|
+
from dataclasses import dataclass, field
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from typing import Optional
|
|
10
|
+
|
|
11
|
+
from proof_engine_registry.client import RegistryClient, LookupHit
|
|
12
|
+
from proof_engine_registry.config import Registry, load_registries
|
|
13
|
+
|
|
14
|
+
from proof_engine_wiki.markers import Marker, find_markers, replace_markers
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@dataclass
|
|
18
|
+
class IngestResult:
|
|
19
|
+
path: Path
|
|
20
|
+
markers: list[Marker]
|
|
21
|
+
resolved_from_registry: int = 0
|
|
22
|
+
generated: int = 0
|
|
23
|
+
misses: int = 0
|
|
24
|
+
errors: list[str] = field(default_factory=list)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def _hit_to_embed(hit: LookupHit, claim_text: str) -> str:
|
|
28
|
+
"""Format a successful lookup as inline Markdown: link + badge."""
|
|
29
|
+
return (
|
|
30
|
+
f"[{claim_text}]({hit.proof_url}) "
|
|
31
|
+
f"})"
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def ingest_page(
|
|
36
|
+
path: Path,
|
|
37
|
+
registries: Optional[list[Registry]] = None,
|
|
38
|
+
*,
|
|
39
|
+
registry_only: bool = False,
|
|
40
|
+
dry_run: bool = False,
|
|
41
|
+
model: str = "sonnet",
|
|
42
|
+
proof_output_base: Optional[Path] = None,
|
|
43
|
+
) -> IngestResult:
|
|
44
|
+
path = Path(path)
|
|
45
|
+
original_text = path.read_text()
|
|
46
|
+
markers = find_markers(original_text)
|
|
47
|
+
|
|
48
|
+
result = IngestResult(path=path, markers=markers)
|
|
49
|
+
if not markers:
|
|
50
|
+
return result
|
|
51
|
+
|
|
52
|
+
regs = registries if registries is not None else load_registries()
|
|
53
|
+
client = RegistryClient(regs) if regs else None
|
|
54
|
+
|
|
55
|
+
replacements: dict[tuple[int, int], str] = {}
|
|
56
|
+
|
|
57
|
+
for m in markers:
|
|
58
|
+
hit = client.lookup(m.claim) if client else None
|
|
59
|
+
if hit is not None:
|
|
60
|
+
replacements[m.span] = _hit_to_embed(hit, m.claim)
|
|
61
|
+
result.resolved_from_registry += 1
|
|
62
|
+
continue
|
|
63
|
+
|
|
64
|
+
if registry_only:
|
|
65
|
+
result.misses += 1
|
|
66
|
+
continue
|
|
67
|
+
|
|
68
|
+
# Commission a new proof via the Proof Engine verify CLI.
|
|
69
|
+
if proof_output_base is None:
|
|
70
|
+
proof_output_base = path.parent / ".proofs"
|
|
71
|
+
proof_output_base.mkdir(parents=True, exist_ok=True)
|
|
72
|
+
output_dir = proof_output_base / _slugify(m.claim)
|
|
73
|
+
|
|
74
|
+
verdict = _invoke_verify(m.claim, model, output_dir)
|
|
75
|
+
if verdict is None:
|
|
76
|
+
result.errors.append(f"verify failed for: {m.claim[:80]}")
|
|
77
|
+
result.misses += 1
|
|
78
|
+
continue
|
|
79
|
+
|
|
80
|
+
# After generation, the proof isn't yet in any registry; produce a
|
|
81
|
+
# local link to the output dir until the user publishes.
|
|
82
|
+
embed = (
|
|
83
|
+
f"[{m.claim}]({output_dir.as_posix()}/proof.md) "
|
|
84
|
+
f"<!-- Proof generated; run `proof-engine-wiki publish "
|
|
85
|
+
f"{output_dir}` to add to your registry. -->"
|
|
86
|
+
)
|
|
87
|
+
replacements[m.span] = embed
|
|
88
|
+
result.generated += 1
|
|
89
|
+
|
|
90
|
+
if replacements and not dry_run:
|
|
91
|
+
new_text = replace_markers(original_text, replacements)
|
|
92
|
+
path.write_text(new_text)
|
|
93
|
+
|
|
94
|
+
return result
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def _slugify(text: str) -> str:
|
|
98
|
+
import re
|
|
99
|
+
s = re.sub(r"[^a-z0-9]+", "-", text.lower()).strip("-")
|
|
100
|
+
return s[:60] or "claim"
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def _invoke_verify(claim: str, model: str, output_dir: Path) -> Optional[dict]:
|
|
104
|
+
"""Call `proof-engine verify` and parse the JSON verdict."""
|
|
105
|
+
import json
|
|
106
|
+
script = _find_verify_cli()
|
|
107
|
+
if script is None:
|
|
108
|
+
return None
|
|
109
|
+
proc = subprocess.run(
|
|
110
|
+
[sys.executable, str(script),
|
|
111
|
+
"--claim", claim,
|
|
112
|
+
"--model", model,
|
|
113
|
+
"--output-dir", str(output_dir),
|
|
114
|
+
"--json"],
|
|
115
|
+
capture_output=True, text=True,
|
|
116
|
+
)
|
|
117
|
+
if not proc.stdout:
|
|
118
|
+
return None
|
|
119
|
+
try:
|
|
120
|
+
return json.loads(proc.stdout)
|
|
121
|
+
except json.JSONDecodeError:
|
|
122
|
+
return None
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def _find_verify_cli() -> Optional[Path]:
|
|
126
|
+
"""Locate the verify_cli.py script. Search the same repo first."""
|
|
127
|
+
import os
|
|
128
|
+
env_path = os.environ.get("PROOF_ENGINE_VERIFY_CLI")
|
|
129
|
+
if env_path:
|
|
130
|
+
p = Path(env_path)
|
|
131
|
+
if p.exists():
|
|
132
|
+
return p
|
|
133
|
+
# Walk up from this file looking for tools/verify_cli.py in the repo.
|
|
134
|
+
for parent in Path(__file__).resolve().parents:
|
|
135
|
+
candidate = parent / "tools" / "verify_cli.py"
|
|
136
|
+
if candidate.exists():
|
|
137
|
+
return candidate
|
|
138
|
+
return None
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"""Lint a wiki directory: unresolved markers, stale proofs, broken badges."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import re
|
|
6
|
+
from dataclasses import dataclass
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
from proof_engine_wiki.markers import find_markers
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
_PROOF_LINK_RE = re.compile(
|
|
13
|
+
r"\[([^\]]+)\]\((?P<url>https?://[^)]+/proofs/[^)]+/)\)"
|
|
14
|
+
)
|
|
15
|
+
_BADGE_IMG_RE = re.compile(
|
|
16
|
+
r"!\[proof\]\((?P<url>https?://[^)]+/badge\.svg)\)"
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@dataclass(frozen=True)
|
|
21
|
+
class LintFinding:
|
|
22
|
+
path: Path
|
|
23
|
+
line: int
|
|
24
|
+
kind: str # unresolved_marker | stale_proof | badge_unreachable
|
|
25
|
+
message: str
|
|
26
|
+
detail: str = ""
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def lint_wiki(
|
|
30
|
+
root: Path,
|
|
31
|
+
*,
|
|
32
|
+
skip_network: bool = False,
|
|
33
|
+
) -> list[LintFinding]:
|
|
34
|
+
root = Path(root)
|
|
35
|
+
findings: list[LintFinding] = []
|
|
36
|
+
for md in sorted(root.rglob("*.md")):
|
|
37
|
+
findings.extend(_lint_file(md, skip_network=skip_network))
|
|
38
|
+
return findings
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _lint_file(path: Path, *, skip_network: bool) -> list[LintFinding]:
|
|
42
|
+
text = path.read_text()
|
|
43
|
+
out: list[LintFinding] = []
|
|
44
|
+
|
|
45
|
+
# Unresolved markers.
|
|
46
|
+
for m in find_markers(text):
|
|
47
|
+
line = text[: m.span[0]].count("\n") + 1
|
|
48
|
+
out.append(LintFinding(
|
|
49
|
+
path=path, line=line,
|
|
50
|
+
kind="unresolved_marker",
|
|
51
|
+
message=f"unresolved {{{{prove:}}}} marker",
|
|
52
|
+
detail=m.claim,
|
|
53
|
+
))
|
|
54
|
+
|
|
55
|
+
# Optionally verify each embedded proof link is still reachable.
|
|
56
|
+
if not skip_network:
|
|
57
|
+
for m in _PROOF_LINK_RE.finditer(text):
|
|
58
|
+
url = m.group("url")
|
|
59
|
+
if not _url_alive(url):
|
|
60
|
+
line = text[: m.start()].count("\n") + 1
|
|
61
|
+
out.append(LintFinding(
|
|
62
|
+
path=path, line=line,
|
|
63
|
+
kind="stale_proof",
|
|
64
|
+
message=f"proof URL not reachable: {url}",
|
|
65
|
+
))
|
|
66
|
+
|
|
67
|
+
return out
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def _url_alive(url: str, timeout: float = 5.0) -> bool:
|
|
71
|
+
import requests
|
|
72
|
+
try:
|
|
73
|
+
r = requests.head(url, timeout=timeout, allow_redirects=True)
|
|
74
|
+
return r.status_code < 400
|
|
75
|
+
except Exception:
|
|
76
|
+
return False
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"""Parser and rewriter for `{{prove: ...}}` markers in wiki prose.
|
|
2
|
+
|
|
3
|
+
Markers are the explicit signal from the author to attach a proof to a claim.
|
|
4
|
+
They are regex-greppable by design — no NLP needed at this layer.
|
|
5
|
+
|
|
6
|
+
Markers inside fenced code blocks (``` ... ```), inline HTML comments
|
|
7
|
+
(<!-- ... -->), and YAML frontmatter at the top of the file are masked
|
|
8
|
+
before matching. Wiki authors who write prose ABOUT the marker syntax
|
|
9
|
+
(documenting it, showing examples) should not accidentally commission a proof.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
import re
|
|
15
|
+
from dataclasses import dataclass
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
# Non-greedy match, allows any content between `prove:` and `}}`, including
|
|
19
|
+
# punctuation. Does NOT cross paragraph boundaries (no `\n\n`).
|
|
20
|
+
_PATTERN = re.compile(
|
|
21
|
+
r"\{\{\s*prove\s*:\s*(?P<claim>(?:(?!\}\}|\n\n).)+?)\s*\}\}",
|
|
22
|
+
re.DOTALL,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
# Masking patterns — each matches a region in which markers should be ignored.
|
|
26
|
+
_CODE_FENCE = re.compile(r"```.*?```", re.DOTALL)
|
|
27
|
+
_INLINE_CODE = re.compile(r"`[^`\n]+`")
|
|
28
|
+
_HTML_COMMENT = re.compile(r"<!--.*?-->", re.DOTALL)
|
|
29
|
+
# YAML frontmatter: leading `---\n...\n---` at file start.
|
|
30
|
+
_FRONTMATTER = re.compile(r"\A---\n.*?\n---\n", re.DOTALL)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@dataclass(frozen=True)
|
|
34
|
+
class Marker:
|
|
35
|
+
claim: str
|
|
36
|
+
# Half-open range in the source text: text[span[0]:span[1]] equals the
|
|
37
|
+
# full `{{prove: ...}}` marker. Matches re.Match.start()/end() semantics.
|
|
38
|
+
span: tuple[int, int]
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _mask_excluded_regions(text: str) -> str:
|
|
42
|
+
"""Return text with excluded regions replaced by spaces of the same length.
|
|
43
|
+
|
|
44
|
+
Same-length replacement preserves offsets so downstream span arithmetic
|
|
45
|
+
still matches the original text.
|
|
46
|
+
"""
|
|
47
|
+
out = list(text)
|
|
48
|
+
for pat in (_FRONTMATTER, _CODE_FENCE, _INLINE_CODE, _HTML_COMMENT):
|
|
49
|
+
for m in pat.finditer(text):
|
|
50
|
+
for i in range(m.start(), m.end()):
|
|
51
|
+
# Keep newlines to preserve line numbers in lint output.
|
|
52
|
+
if out[i] != "\n":
|
|
53
|
+
out[i] = " "
|
|
54
|
+
return "".join(out)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def find_markers(text: str) -> list[Marker]:
|
|
58
|
+
"""Find `{{prove: ...}}` markers, skipping code blocks, comments, frontmatter."""
|
|
59
|
+
masked = _mask_excluded_regions(text)
|
|
60
|
+
out: list[Marker] = []
|
|
61
|
+
for m in _PATTERN.finditer(masked):
|
|
62
|
+
# Claim text must come from the ORIGINAL string, not the masked copy —
|
|
63
|
+
# a marker that straddles into an inline code span would be masked,
|
|
64
|
+
# but a marker fully outside gives the correct claim text from `text`.
|
|
65
|
+
claim = text[m.start():m.end()]
|
|
66
|
+
# Re-parse the claim out of the full marker with the same pattern.
|
|
67
|
+
inner = _PATTERN.fullmatch(claim)
|
|
68
|
+
if inner is None:
|
|
69
|
+
continue
|
|
70
|
+
out.append(Marker(
|
|
71
|
+
claim=inner.group("claim").strip(),
|
|
72
|
+
span=(m.start(), m.end()),
|
|
73
|
+
))
|
|
74
|
+
return out
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def replace_markers(text: str, replacements: dict[tuple[int, int], str]) -> str:
|
|
78
|
+
"""Replace each (start, end) span with the given string.
|
|
79
|
+
|
|
80
|
+
Spans must not overlap. Iterates back-to-front so earlier spans aren't
|
|
81
|
+
invalidated by replacements.
|
|
82
|
+
"""
|
|
83
|
+
if not replacements:
|
|
84
|
+
return text
|
|
85
|
+
sorted_spans = sorted(replacements.keys(), key=lambda s: s[0], reverse=True)
|
|
86
|
+
out = text
|
|
87
|
+
for span in sorted_spans:
|
|
88
|
+
start, end = span
|
|
89
|
+
out = out[:start] + replacements[span] + out[end:]
|
|
90
|
+
return out
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: proof-engine-wiki
|
|
3
|
+
Version: 1.33.0
|
|
4
|
+
Summary: Attach verified Proof Engine proofs to LLM-wiki claims.
|
|
5
|
+
Author-email: Yaniv Golan <yaniv@lool.vc>
|
|
6
|
+
License: MIT License
|
|
7
|
+
|
|
8
|
+
Copyright (c) 2026 Yaniv Golan
|
|
9
|
+
|
|
10
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
11
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
12
|
+
in the Software without restriction, including without limitation the rights
|
|
13
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
14
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
15
|
+
furnished to do so, subject to the following conditions:
|
|
16
|
+
|
|
17
|
+
The above copyright notice and this permission notice shall be included in all
|
|
18
|
+
copies or substantial portions of the Software.
|
|
19
|
+
|
|
20
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
21
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
22
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
23
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
24
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
25
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
26
|
+
SOFTWARE.
|
|
27
|
+
|
|
28
|
+
Project-URL: Homepage, https://proofengine.info
|
|
29
|
+
Project-URL: Repository, https://github.com/yaniv-golan/proof-engine
|
|
30
|
+
Project-URL: Documentation, https://github.com/yaniv-golan/proof-engine/blob/main/packages/proof-engine-wiki/README.md
|
|
31
|
+
Project-URL: Issues, https://github.com/yaniv-golan/proof-engine/issues
|
|
32
|
+
Project-URL: Changelog, https://github.com/yaniv-golan/proof-engine/blob/main/CHANGELOG.md
|
|
33
|
+
Project-URL: Source, https://github.com/yaniv-golan/proof-engine/tree/main/packages/proof-engine-wiki
|
|
34
|
+
Requires-Python: >=3.11
|
|
35
|
+
Description-Content-Type: text/markdown
|
|
36
|
+
License-File: LICENSE
|
|
37
|
+
Requires-Dist: proof-citations>=0.1
|
|
38
|
+
Requires-Dist: proof-engine-registry>=0.1
|
|
39
|
+
Requires-Dist: requests>=2.31
|
|
40
|
+
Dynamic: license-file
|
|
41
|
+
|
|
42
|
+
# proof-engine-wiki
|
|
43
|
+
|
|
44
|
+
Attach Proof Engine proofs to LLM-wiki claims.
|
|
45
|
+
|
|
46
|
+
## Install
|
|
47
|
+
|
|
48
|
+
pip install proof-engine-wiki
|
|
49
|
+
|
|
50
|
+
## Marker syntax
|
|
51
|
+
|
|
52
|
+
Authors mark claims they want proven:
|
|
53
|
+
|
|
54
|
+
The US dollar has {{prove: lost 15% of its purchasing power since 2020}}.
|
|
55
|
+
|
|
56
|
+
## Ingest
|
|
57
|
+
|
|
58
|
+
proof-engine-wiki ingest PAGE.md
|
|
59
|
+
|
|
60
|
+
Extracts all `{{prove:}}` markers, looks up configured registries,
|
|
61
|
+
commissions a new proof only for misses, rewrites the file with inline
|
|
62
|
+
badges and links.
|
|
63
|
+
|
|
64
|
+
## Lint
|
|
65
|
+
|
|
66
|
+
proof-engine-wiki lint WIKI_DIR/
|
|
67
|
+
|
|
68
|
+
Scans every `.md` file under the directory and reports:
|
|
69
|
+
|
|
70
|
+
- `unresolved_marker` — `{{prove:}}` markers in the page that haven't
|
|
71
|
+
been resolved yet (run `ingest` to resolve them).
|
|
72
|
+
- `stale_proof` — embedded proof URLs that no longer respond to a HEAD
|
|
73
|
+
request (the proof was retracted or the registry moved).
|
|
74
|
+
|
|
75
|
+
Pass `--skip-network` to suppress URL reachability checks (faster CI;
|
|
76
|
+
catches only `unresolved_marker`).
|
|
77
|
+
|
|
78
|
+
## Registry-only mode
|
|
79
|
+
|
|
80
|
+
Add `--registry-only` to `ingest` to skip new-proof commissioning
|
|
81
|
+
entirely. Useful for CI: if every `{{prove:}}` claim already has a
|
|
82
|
+
registered proof, ingest runs offline and quickly. Misses are reported,
|
|
83
|
+
not commissioned.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
proof_engine_wiki/__init__.py,sha256=MZbvZcYrJAKKkCAS5EFzX8-qr_QTPjcuVb7T1YZcbbI,96
|
|
2
|
+
proof_engine_wiki/cli.py,sha256=5hH6Riu7k9tFAeGr752MpF2nSPFsGODavQuXG45Ng4I,3168
|
|
3
|
+
proof_engine_wiki/ingest.py,sha256=-s_aPZhPkvVWx1evZf3BFzPOGKhzMPikM51iC7Jll7I,4199
|
|
4
|
+
proof_engine_wiki/lint.py,sha256=UtlhvzIXbGMCTGB7sB2c5_IuluyJkTybhtZXbrgu63E,2056
|
|
5
|
+
proof_engine_wiki/markers.py,sha256=jEM0aEPKvoudsA7dBGowxcJ197Qdk6tzn8MIL_vPUDA,3363
|
|
6
|
+
proof_engine_wiki-1.33.0.dist-info/licenses/LICENSE,sha256=zTTaGO6alQLutSENMjseDqP5xEDqs69DylIBhe2KsEE,1068
|
|
7
|
+
proof_engine_wiki-1.33.0.dist-info/METADATA,sha256=H09i-yKN9-p-P32878joczOA9duhUgPzqq4vRl5piPs,3304
|
|
8
|
+
proof_engine_wiki-1.33.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
9
|
+
proof_engine_wiki-1.33.0.dist-info/entry_points.txt,sha256=gRAOocT4ISwdYYQiCx5qaExzcmFjApfIbfOuEclwfck,65
|
|
10
|
+
proof_engine_wiki-1.33.0.dist-info/top_level.txt,sha256=RiCV_bxWBQsfFbAbnFHYyd7uJbs4gj32OyPGqqxjHbY,18
|
|
11
|
+
proof_engine_wiki-1.33.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Yaniv Golan
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
proof_engine_wiki
|