machinechecked 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.
- machinechecked-0.1.0.dist-info/METADATA +108 -0
- machinechecked-0.1.0.dist-info/RECORD +58 -0
- machinechecked-0.1.0.dist-info/WHEEL +5 -0
- machinechecked-0.1.0.dist-info/entry_points.txt +3 -0
- machinechecked-0.1.0.dist-info/licenses/LICENSE +201 -0
- machinechecked-0.1.0.dist-info/top_level.txt +1 -0
- prooflens/__init__.py +1 -0
- prooflens/__main__.py +3 -0
- prooflens/assess.py +504 -0
- prooflens/audit.py +115 -0
- prooflens/bundle.py +70 -0
- prooflens/cli.py +542 -0
- prooflens/config.py +145 -0
- prooflens/data/ProofLensProbe.lean +469 -0
- prooflens/data/prooflens.sty +75 -0
- prooflens/data/schema/evidence.schema.json +24 -0
- prooflens/data/schema/inventory.schema.json +55 -0
- prooflens/data/schema/manifest-claim.schema.json +126 -0
- prooflens/data/schema/manifest-index.schema.json +128 -0
- prooflens/evidence.py +60 -0
- prooflens/export.py +227 -0
- prooflens/formalization.py +106 -0
- prooflens/manifest.py +296 -0
- prooflens/pdfclaims.py +129 -0
- prooflens/pipeline.py +331 -0
- prooflens/probe.py +126 -0
- prooflens/promote.py +204 -0
- prooflens/review_queue.py +138 -0
- prooflens/reviews.py +105 -0
- prooflens/schemas.py +19 -0
- prooflens/server.py +63 -0
- prooflens/simple.py +628 -0
- prooflens/sources.py +164 -0
- prooflens/tex.py +408 -0
- prooflens/util.py +66 -0
- prooflens/web/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
- prooflens/web/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
- prooflens/web/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
- prooflens/web/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
- prooflens/web/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
- prooflens/web/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
- prooflens/web/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
- prooflens/web/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
- prooflens/web/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
- prooflens/web/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
- prooflens/web/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
- prooflens/web/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
- prooflens/web/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
- prooflens/web/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
- prooflens/web/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
- prooflens/web/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
- prooflens/web/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
- prooflens/web/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
- prooflens/web/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
- prooflens/web/assets/index-B2GDDbsW.css +1 -0
- prooflens/web/assets/index-DN7uLe7p.js +285 -0
- prooflens/web/assets/pdf.worker.min-yatZIOMy.mjs +21 -0
- prooflens/web/index.html +14 -0
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
% prooflens.sty -- records where every numbered claim of a paper is typeset.
|
|
2
|
+
%
|
|
3
|
+
% Loaded before \documentclass by `prooflens tex` (latexmk -usepretex), so the paper's source is
|
|
4
|
+
% not modified. For every tracked environment it writes to \jobname.plx, one record per line:
|
|
5
|
+
%
|
|
6
|
+
% paper <width> <height> page size in sp
|
|
7
|
+
% begin <id> <env> <line> <file> where the environment opens in the source
|
|
8
|
+
% prev <id> <label> \@currentlabel when it opens (a head number
|
|
9
|
+
% equal to it was not stepped by the environment)
|
|
10
|
+
% (the file with its path as \input gave it)
|
|
11
|
+
% number <id> <currentlabel> the number the environment received
|
|
12
|
+
% label <id> <name> <currentlabel> every \label inside the environment
|
|
13
|
+
% pos <id> <begin|head|end> <page> <x> <y> position at shipout, in sp from bottom left;
|
|
14
|
+
% head is the baseline of the first line
|
|
15
|
+
%
|
|
16
|
+
% The environments tracked are \prooflensEnvs (a comma list), set by the caller before loading,
|
|
17
|
+
% or the default list below. Requires pdfTeX or LuaTeX (\pdfsavepos) and LaTeX 2020-10 or later
|
|
18
|
+
% (hooks, \CurrentFile, \ReadonlyShipoutCounter).
|
|
19
|
+
\NeedsTeXFormat{LaTeX2e}[2020/10/01]
|
|
20
|
+
\ProvidesPackage{prooflens}[2026/10/15 ProofLens claim anchors]
|
|
21
|
+
|
|
22
|
+
\ifdefined\pdfsavepos\else
|
|
23
|
+
\ifdefined\savepos
|
|
24
|
+
\let\pdfsavepos\savepos \let\pdflastxpos\lastxpos \let\pdflastypos\lastypos
|
|
25
|
+
\fi
|
|
26
|
+
\fi
|
|
27
|
+
|
|
28
|
+
\ifdefined\prooflensEnvs\else
|
|
29
|
+
\def\prooflensEnvs{theorem,lemma,proposition,corollary,definition,assumption,remark,%
|
|
30
|
+
example,conjecture,claim,hypothesis,convention}
|
|
31
|
+
\fi
|
|
32
|
+
|
|
33
|
+
\newwrite\plx@out
|
|
34
|
+
\newcount\plx@id
|
|
35
|
+
\def\plx@cur{0}
|
|
36
|
+
|
|
37
|
+
\AddToHook{begindocument/end}{%
|
|
38
|
+
\immediate\openout\plx@out=\jobname.plx\relax
|
|
39
|
+
\immediate\write\plx@out{paper \the\paperwidth\space\the\paperheight}}
|
|
40
|
+
\AddToHook{enddocument/end}{\immediate\closeout\plx@out}
|
|
41
|
+
|
|
42
|
+
% A position record, written at shipout so that the page and coordinates are final.
|
|
43
|
+
\def\plx@pos#1{%
|
|
44
|
+
\edef\plx@tmp{\noexpand\write\plx@out{pos \plx@cur\space #1
|
|
45
|
+
\noexpand\the\noexpand\ReadonlyShipoutCounter\space
|
|
46
|
+
\noexpand\the\noexpand\pdflastxpos\space\noexpand\the\noexpand\pdflastypos}}%
|
|
47
|
+
\pdfsavepos\plx@tmp}
|
|
48
|
+
|
|
49
|
+
\def\plx@begin#1{%
|
|
50
|
+
\global\advance\plx@id\@ne
|
|
51
|
+
\edef\plx@cur{\the\plx@id}%
|
|
52
|
+
\immediate\write\plx@out{begin \plx@cur\space #1 \the\inputlineno\space\CurrentFilePath\ifx\CurrentFilePath\@empty\else/\fi\CurrentFile}%
|
|
53
|
+
\protected@edef\plx@tmp{\@currentlabel}%
|
|
54
|
+
\immediate\write\plx@out{prev \plx@cur\space\detokenize\expandafter{\plx@tmp}}%
|
|
55
|
+
\plx@pos{begin}%
|
|
56
|
+
% The number is \@currentlabel when the first paragraph of the environment (its head) starts.
|
|
57
|
+
\AddToHookNext{para/begin}{%
|
|
58
|
+
\plx@pos{head}%
|
|
59
|
+
\protected@edef\plx@tmp{\@currentlabel}%
|
|
60
|
+
\immediate\write\plx@out{number \plx@cur\space\detokenize\expandafter{\plx@tmp}}}%
|
|
61
|
+
\let\plx@savedlabel\label
|
|
62
|
+
\def\label##1{%
|
|
63
|
+
\protected@edef\plx@tmp{\@currentlabel}%
|
|
64
|
+
\immediate\write\plx@out{label \plx@cur\space\detokenize{##1} \detokenize\expandafter{\plx@tmp}}%
|
|
65
|
+
\plx@savedlabel{##1}}}
|
|
66
|
+
|
|
67
|
+
\def\plx@end{\plx@pos{end}}
|
|
68
|
+
|
|
69
|
+
\@for\plx@env:=\prooflensEnvs\do{%
|
|
70
|
+
\edef\plx@tmp{%
|
|
71
|
+
\noexpand\AddToHook{env/\plx@env/begin}{\noexpand\plx@begin{\plx@env}}%
|
|
72
|
+
\noexpand\AddToHook{env/\plx@env/end}{\noexpand\plx@end}}%
|
|
73
|
+
\plx@tmp}
|
|
74
|
+
|
|
75
|
+
\endinput
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://github.com/cgarryZA/ProofLens/schema/evidence.schema.json",
|
|
4
|
+
"title": "ProofLens evidence record",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"required": ["id", "created", "body"],
|
|
7
|
+
"properties": {
|
|
8
|
+
"id": {"type": "string", "pattern": "^[0-9a-f]{64}$"},
|
|
9
|
+
"created": {"type": "string"},
|
|
10
|
+
"body": {
|
|
11
|
+
"type": "object",
|
|
12
|
+
"required": ["schema", "provenance", "inventory", "reviews", "lean", "tex", "assessment"],
|
|
13
|
+
"properties": {
|
|
14
|
+
"schema": {"const": "prooflens/evidence@0"},
|
|
15
|
+
"provenance": {"type": "object", "required": ["tool", "project", "papers"]},
|
|
16
|
+
"inventory": {"type": "object", "required": ["claims"]},
|
|
17
|
+
"reviews": {"type": "object", "required": ["files", "records"]},
|
|
18
|
+
"lean": {"type": ["object", "null"]},
|
|
19
|
+
"tex": {"type": "object"},
|
|
20
|
+
"assessment": {"type": "object", "required": ["claims", "findings"]}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://github.com/cgarryZA/ProofLens/schema/inventory.schema.json",
|
|
4
|
+
"title": "ProofLens claim inventory",
|
|
5
|
+
"description": "Every claim of the papers, with its scope and, for a formal claim, the clauses mapped to Lean declarations.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"required": ["claims"],
|
|
8
|
+
"properties": {
|
|
9
|
+
"note": {"type": "string"},
|
|
10
|
+
"papers": {"type": "object"},
|
|
11
|
+
"claims": {"type": "array", "items": {"$ref": "#/$defs/claim"}}
|
|
12
|
+
},
|
|
13
|
+
"$defs": {
|
|
14
|
+
"scope": {"enum": ["formal", "definition", "expository", "literature", "empirical",
|
|
15
|
+
"proof-step", "part-of", "duplicate"]},
|
|
16
|
+
"claim": {
|
|
17
|
+
"type": "object",
|
|
18
|
+
"required": ["id", "paper", "scope", "clauses"],
|
|
19
|
+
"properties": {
|
|
20
|
+
"id": {"type": "string", "pattern": "^[A-Za-z0-9]+:.+$"},
|
|
21
|
+
"paper": {"type": "string"},
|
|
22
|
+
"commit": {"type": ["string", "null"]},
|
|
23
|
+
"kind": {"type": "string"},
|
|
24
|
+
"number": {"type": "string"},
|
|
25
|
+
"title": {"type": "string"},
|
|
26
|
+
"label": {"type": ["string", "null"]},
|
|
27
|
+
"location": {"type": ["string", "null"]},
|
|
28
|
+
"source_sha256": {"type": ["string", "null"], "pattern": "^[0-9a-f]{64}$"},
|
|
29
|
+
"scope": {"$ref": "#/$defs/scope"},
|
|
30
|
+
"scope_note": {"type": "string"},
|
|
31
|
+
"scope_reviewed": {"type": "boolean"},
|
|
32
|
+
"clauses": {"type": "array", "items": {"$ref": "#/$defs/clause"}}
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
"clause": {
|
|
36
|
+
"type": "object",
|
|
37
|
+
"required": ["name"],
|
|
38
|
+
"properties": {
|
|
39
|
+
"name": {"type": "string"},
|
|
40
|
+
"spec": {"type": ["string", "null"]},
|
|
41
|
+
"accept": {"type": ["string", "null"]},
|
|
42
|
+
"refute": {"type": ["string", "null"]},
|
|
43
|
+
"corrects": {"type": ["string", "null"]},
|
|
44
|
+
"witness": {"type": ["string", "null"]},
|
|
45
|
+
"defs": {"type": "array", "items": {"type": "string"}},
|
|
46
|
+
"regimes": {"type": "array", "items": {
|
|
47
|
+
"type": "object", "required": ["name"],
|
|
48
|
+
"properties": {"name": {"type": "string"}, "description": {"type": "string"},
|
|
49
|
+
"witness": {"type": ["string", "null"]}}}}
|
|
50
|
+
},
|
|
51
|
+
"not": {"required": ["accept", "refute"],
|
|
52
|
+
"properties": {"accept": {"type": "string"}, "refute": {"type": "string"}}}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://github.com/cgarryZA/ProofLens/schema/manifest-claim.schema.json",
|
|
4
|
+
"title": "ProofLens claim passport",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"required": [
|
|
7
|
+
"schema",
|
|
8
|
+
"release",
|
|
9
|
+
"id",
|
|
10
|
+
"paper",
|
|
11
|
+
"status",
|
|
12
|
+
"clauses",
|
|
13
|
+
"findings",
|
|
14
|
+
"decls"
|
|
15
|
+
],
|
|
16
|
+
"properties": {
|
|
17
|
+
"schema": {
|
|
18
|
+
"const": "prooflens/manifest@0"
|
|
19
|
+
},
|
|
20
|
+
"release": {
|
|
21
|
+
"type": "string"
|
|
22
|
+
},
|
|
23
|
+
"id": {
|
|
24
|
+
"type": "string"
|
|
25
|
+
},
|
|
26
|
+
"status": {
|
|
27
|
+
"type": "string"
|
|
28
|
+
},
|
|
29
|
+
"statement_tex": {
|
|
30
|
+
"type": [
|
|
31
|
+
"string",
|
|
32
|
+
"null"
|
|
33
|
+
]
|
|
34
|
+
},
|
|
35
|
+
"clauses": {
|
|
36
|
+
"type": "array",
|
|
37
|
+
"items": {
|
|
38
|
+
"type": "object",
|
|
39
|
+
"required": [
|
|
40
|
+
"name",
|
|
41
|
+
"state",
|
|
42
|
+
"ladder"
|
|
43
|
+
],
|
|
44
|
+
"properties": {
|
|
45
|
+
"state": {
|
|
46
|
+
"enum": [
|
|
47
|
+
"unspecified",
|
|
48
|
+
"unchecked",
|
|
49
|
+
"open",
|
|
50
|
+
"proved",
|
|
51
|
+
"refuted",
|
|
52
|
+
"malformed",
|
|
53
|
+
"stated"
|
|
54
|
+
]
|
|
55
|
+
},
|
|
56
|
+
"ladder": {
|
|
57
|
+
"type": "array",
|
|
58
|
+
"items": {
|
|
59
|
+
"type": "object",
|
|
60
|
+
"required": [
|
|
61
|
+
"rung",
|
|
62
|
+
"state"
|
|
63
|
+
],
|
|
64
|
+
"properties": {
|
|
65
|
+
"state": {
|
|
66
|
+
"enum": [
|
|
67
|
+
"pass",
|
|
68
|
+
"fail",
|
|
69
|
+
"open",
|
|
70
|
+
"author",
|
|
71
|
+
"none",
|
|
72
|
+
"n/a",
|
|
73
|
+
"pdf-only",
|
|
74
|
+
"not-run",
|
|
75
|
+
"unverified"
|
|
76
|
+
]
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
"findings": {
|
|
85
|
+
"type": "array",
|
|
86
|
+
"items": {
|
|
87
|
+
"$ref": "#/$defs/finding"
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
"decls": {
|
|
91
|
+
"type": "object",
|
|
92
|
+
"additionalProperties": {
|
|
93
|
+
"type": "string",
|
|
94
|
+
"pattern": "^[0-9a-f]{24}$"
|
|
95
|
+
},
|
|
96
|
+
"description": "Each declaration of the claim's closures, by name, with the key of its record data/decls/<key>.json (the first 24 hex digits of the SHA-256 of the record)"
|
|
97
|
+
},
|
|
98
|
+
"blockers": {
|
|
99
|
+
"type": "array",
|
|
100
|
+
"items": {
|
|
101
|
+
"type": "string"
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
},
|
|
105
|
+
"$defs": {
|
|
106
|
+
"finding": {
|
|
107
|
+
"type": "object",
|
|
108
|
+
"required": [
|
|
109
|
+
"id",
|
|
110
|
+
"tier",
|
|
111
|
+
"code",
|
|
112
|
+
"subject",
|
|
113
|
+
"message"
|
|
114
|
+
],
|
|
115
|
+
"properties": {
|
|
116
|
+
"tier": {
|
|
117
|
+
"enum": [
|
|
118
|
+
"violation",
|
|
119
|
+
"warning",
|
|
120
|
+
"obligation"
|
|
121
|
+
]
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://github.com/cgarryZA/ProofLens/schema/manifest-index.schema.json",
|
|
4
|
+
"title": "ProofLens manifest index",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"required": [
|
|
7
|
+
"schema",
|
|
8
|
+
"release",
|
|
9
|
+
"evidence",
|
|
10
|
+
"papers",
|
|
11
|
+
"claims",
|
|
12
|
+
"summary",
|
|
13
|
+
"classes",
|
|
14
|
+
"findings"
|
|
15
|
+
],
|
|
16
|
+
"properties": {
|
|
17
|
+
"schema": {
|
|
18
|
+
"const": "prooflens/manifest@0"
|
|
19
|
+
},
|
|
20
|
+
"release": {
|
|
21
|
+
"type": "string"
|
|
22
|
+
},
|
|
23
|
+
"evidence": {
|
|
24
|
+
"type": "string",
|
|
25
|
+
"pattern": "^[0-9a-f]{64}$"
|
|
26
|
+
},
|
|
27
|
+
"created": {
|
|
28
|
+
"type": "string"
|
|
29
|
+
},
|
|
30
|
+
"project": {
|
|
31
|
+
"type": "object"
|
|
32
|
+
},
|
|
33
|
+
"lean": {
|
|
34
|
+
"type": [
|
|
35
|
+
"object",
|
|
36
|
+
"null"
|
|
37
|
+
]
|
|
38
|
+
},
|
|
39
|
+
"tool": {
|
|
40
|
+
"type": "object"
|
|
41
|
+
},
|
|
42
|
+
"papers": {
|
|
43
|
+
"type": "array",
|
|
44
|
+
"items": {
|
|
45
|
+
"type": "object",
|
|
46
|
+
"required": [
|
|
47
|
+
"id",
|
|
48
|
+
"mode",
|
|
49
|
+
"pdf"
|
|
50
|
+
],
|
|
51
|
+
"properties": {
|
|
52
|
+
"id": {
|
|
53
|
+
"type": "string"
|
|
54
|
+
},
|
|
55
|
+
"mode": {
|
|
56
|
+
"enum": [
|
|
57
|
+
"latex",
|
|
58
|
+
"pdf"
|
|
59
|
+
]
|
|
60
|
+
},
|
|
61
|
+
"pdf": {
|
|
62
|
+
"type": [
|
|
63
|
+
"string",
|
|
64
|
+
"null"
|
|
65
|
+
]
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
"summary": {
|
|
71
|
+
"type": "object"
|
|
72
|
+
},
|
|
73
|
+
"findings": {
|
|
74
|
+
"type": "object"
|
|
75
|
+
},
|
|
76
|
+
"claims": {
|
|
77
|
+
"type": "array",
|
|
78
|
+
"items": {
|
|
79
|
+
"type": "object",
|
|
80
|
+
"required": [
|
|
81
|
+
"id",
|
|
82
|
+
"paper",
|
|
83
|
+
"status",
|
|
84
|
+
"class",
|
|
85
|
+
"file",
|
|
86
|
+
"counts"
|
|
87
|
+
],
|
|
88
|
+
"properties": {
|
|
89
|
+
"id": {
|
|
90
|
+
"type": "string"
|
|
91
|
+
},
|
|
92
|
+
"paper": {
|
|
93
|
+
"type": "string"
|
|
94
|
+
},
|
|
95
|
+
"status": {
|
|
96
|
+
"type": "string"
|
|
97
|
+
},
|
|
98
|
+
"class": {
|
|
99
|
+
"enum": [
|
|
100
|
+
"accepted",
|
|
101
|
+
"proved",
|
|
102
|
+
"refuted",
|
|
103
|
+
"open",
|
|
104
|
+
"malformed",
|
|
105
|
+
"out-of-scope",
|
|
106
|
+
"unspecified"
|
|
107
|
+
]
|
|
108
|
+
},
|
|
109
|
+
"anchor": {
|
|
110
|
+
"type": [
|
|
111
|
+
"object",
|
|
112
|
+
"null"
|
|
113
|
+
]
|
|
114
|
+
},
|
|
115
|
+
"file": {
|
|
116
|
+
"type": "string"
|
|
117
|
+
},
|
|
118
|
+
"counts": {
|
|
119
|
+
"type": "object"
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
},
|
|
124
|
+
"search": {
|
|
125
|
+
"type": "string"
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
prooflens/evidence.py
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"""The evidence store: content-addressed, append-only records of what the pipeline established.
|
|
2
|
+
|
|
3
|
+
A record is `{"id", "created", "body"}` with `id` the SHA-256 of the canonical JSON of `body`. A
|
|
4
|
+
new run with any difference produces a new record; an existing record is never rewritten.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import datetime as _dt
|
|
10
|
+
import json
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
|
|
13
|
+
from .util import canonical_json, content_id, read_json
|
|
14
|
+
|
|
15
|
+
SCHEMA = "prooflens/evidence@0"
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class EvidenceError(RuntimeError):
|
|
19
|
+
pass
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def store(out_dir: Path, body: dict) -> str:
|
|
23
|
+
body = dict(body, schema=SCHEMA)
|
|
24
|
+
eid = content_id(body)
|
|
25
|
+
path = out_dir / "evidence" / f"{eid}.json"
|
|
26
|
+
if path.exists():
|
|
27
|
+
old = read_json(path)
|
|
28
|
+
if content_id(old["body"]) != eid:
|
|
29
|
+
raise EvidenceError(f"evidence record {path} does not match its id")
|
|
30
|
+
return eid
|
|
31
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
32
|
+
rec = {"id": eid, "created": _dt.datetime.now(_dt.timezone.utc).isoformat(timespec="seconds"),
|
|
33
|
+
"body": json.loads(canonical_json(body))}
|
|
34
|
+
tmp = path.with_suffix(".tmp")
|
|
35
|
+
tmp.write_text(json.dumps(rec, ensure_ascii=False, sort_keys=True), encoding="utf-8")
|
|
36
|
+
tmp.replace(path)
|
|
37
|
+
return eid
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def load(out_dir: Path, eid: str) -> dict:
|
|
41
|
+
path = out_dir / "evidence" / f"{eid}.json"
|
|
42
|
+
rec = read_json(path)
|
|
43
|
+
if content_id(rec["body"]) != eid:
|
|
44
|
+
raise EvidenceError(f"evidence record {path} does not match its id")
|
|
45
|
+
return rec
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def record_release(out_dir: Path, name: str, eid: str) -> Path:
|
|
49
|
+
"""Name a release; a release name, once given, keeps its evidence."""
|
|
50
|
+
path = out_dir / "releases" / f"{name}.json"
|
|
51
|
+
if path.exists():
|
|
52
|
+
old = read_json(path)
|
|
53
|
+
if old["evidence"] != eid:
|
|
54
|
+
raise EvidenceError(f"release {name} already names evidence {old['evidence']}")
|
|
55
|
+
return path
|
|
56
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
57
|
+
path.write_text(json.dumps({"release": name, "evidence": eid,
|
|
58
|
+
"created": _dt.datetime.now(_dt.timezone.utc)
|
|
59
|
+
.isoformat(timespec="seconds")}, indent=1) + "\n")
|
|
60
|
+
return path
|