provared 0.1.0 → 0.3.0

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/CHANGELOG.md CHANGED
@@ -1,8 +1,297 @@
1
1
  # Changelog
2
2
 
3
- ## Unreleased
3
+ ## 0.3.0 (10 October 2026)
4
4
 
5
- Draft version 0 of the format. Nothing is published or frozen.
5
+ - 2026-10-10: **a development stand-in for a passkey**, `provared/dev`
6
+ in JavaScript and `provared.dev` in Python, so that a first record can
7
+ be made without a browser: `developmentPasskey` (an ES256 key made in
8
+ memory that returns the three values a passkey returns, for the page
9
+ address `http://localhost`), `developmentSlip` (a slip it signed, with
10
+ new keys for the agent, a book holding the slip, and the stand-in's
11
+ thumbprint for a checker) and `developmentRecorder` (the stub writer
12
+ opened under such a slip, in one call). It is not a passkey and no
13
+ person confirms anything through it, so the issuer's name in every
14
+ slip it signs is made to end with " (development)", whatever name is
15
+ given, and the checker prints that name. The library itself (`provared`)
16
+ does not export it, and the checker does not use it. A first record in
17
+ one file: `examples/first-record.mjs` and
18
+ `python/examples/first_record.py`, each run by a test.
19
+ - 2026-10-10: `provared-check --sample` checks the sample record that
20
+ comes with the library, naming the stand-in passkey, the recorder and
21
+ the time-stamp service it was made with as trusted, and prints their
22
+ fingerprints; with `--json` the result alone. A file or another option
23
+ given with it is refused.
24
+ - 2026-10-10: the README is now a short landing page (install, a first
25
+ record, the four parts, what is only here, what a record does not
26
+ prove, where everything else is), and its former body is
27
+ `docs/guide.md`, unchanged but for the additions above. New:
28
+ `SECURITY.md` (how to report a fault in the security of a record) and
29
+ `CONTRIBUTING.md` (fault reports and other implementations welcome;
30
+ code only under a contributor agreement, whose text is not ready yet).
31
+ `package.json` and `python/pyproject.toml` gain a homepage, keywords
32
+ and a longer description. Version 0.3.0 in both, not yet published.
33
+ - 2026-10-10: the pages at prova.red: the home page's first screen now
34
+ shows the checker's summary and the install lines before the four
35
+ parts, with the plain word first and the short name after ("the
36
+ permission (a Slip)"); a first record of your own, in three commands,
37
+ with the file above and the LangChain package; "what the author found
38
+ nowhere else (October 2026)"; the status promises that every published
39
+ version stays on npm and the Python Package Index. The plain-words page
40
+ says that the 25 rounds of review were by AI reviewers and that no
41
+ person other than the author has reviewed the code yet, gives the date
42
+ from which the EU AI Act's logging duty applies (2 December 2027),
43
+ marks its charity example as invented, and uses "flight recorder" only
44
+ as a description. The developer page shows the code that made the
45
+ sample record and says the same about the reviews. All three pages
46
+ gain preview tags, an icon (`favicon.svg`, four coloured squares) and
47
+ a preview image (`preview.png`, drawn from a small page in a headless
48
+ browser), with the content security policy widened by `img-src 'self'`
49
+ only; `robots.txt` and `sitemap.xml` are added, and the workflow copies
50
+ everything in `site/`. Nothing in the library changes for this.
51
+ - 2026-10-10: the pages for prova.red, in `site/`: what a record
52
+ proves, the command-line checker's own answer for the sample record
53
+ (run on Node.js 24.19), how to try it, what is only here, how it is
54
+ built, where it is, a worked example for developers ("An agent goes
55
+ over its limit, and the record shows where") and "Provared in plain
56
+ words", three minutes for a reader who does not write code, with two
57
+ drawings that follow the sample record. No script, no font, no image,
58
+ no form: each page loads nothing from anywhere and keeps nothing about
59
+ a reader, and says so. The drawings carry their colours as plain SVG
60
+ attributes as well as through the style sheet, and the pages load the
61
+ style sheet under a versioned address, so a browser that kept an
62
+ earlier copy still draws them right. A workflow, `.github/workflows/pages.yml`,
63
+ publishes them with GitHub Pages from the main branch, with the
64
+ checking page at `/check/` (with the library and the sample it loads,
65
+ copied as they are) and built as one file at `/provared-check.html`.
66
+ The four actions it uses are GitHub's own, each pinned to the commit
67
+ of a released version. The site is not published until the domain
68
+ points at it. Nothing in the library, the checker or the package
69
+ changes.
70
+ - 2026-10-08: two small Python packages for agent frameworks, in
71
+ `python/integrations/`, each in a folder of its own, which names its
72
+ framework. Each puts every tool call of an agent behind the stub
73
+ writer with no change to the tools: the check before acting is asked,
74
+ the tool runs only if the slip allows it, and a stub is written; a call
75
+ that is not allowed is not run, and the model is told why. Each checks
76
+ the call as the tool receives it: one must come last among the parts
77
+ that wrap tool calls, and refuses to run otherwise; the other wraps
78
+ each of the agent's own sets of tools, wherever it stands. Each works with ordinary
79
+ and asynchronous agents: the stub writer runs in a thread of its own
80
+ for each call, and cancelling a run cancels a tool that is waiting.
81
+ Each is tested with its framework's own stand-in model, inside the
82
+ examples' guard. An independent review found eight faults in the first
83
+ draft, among them a reviewer's change that got past the slip and
84
+ asynchronous agents that could hang; each is fixed and tested. They use
85
+ only the public interface of the `provared` package, which itself still
86
+ names no product. Not yet published.
87
+
88
+ ## 0.2.0 (8 October 2026)
89
+
90
+ - 2026-10-08: version 0.2.0, for the npm package and, for the first
91
+ time, the Python package `provared` on the Python Package Index. Both
92
+ give the same answers, as the shared test files in `test-vectors/`
93
+ show. The version rises from 0.1.0 because the format's rules changed:
94
+ the exact rule for a page address in a slip, weak Ed25519 keys and
95
+ signatures refused, and strict keys in a time-stamp service's
96
+ certificate. Version 0.1.0 accepts a forged time-stamp where the
97
+ person checking names as trusted a service whose certificate has an RSA
98
+ public number of 1; 0.2.0 refuses it. The entries below say what
99
+ changed.
100
+ - 2026-10-08: fixes from an independent review of `record_function`, the
101
+ examples and the wording for a proposed action. None made a book read
102
+ as intact, or within its slip, when it was not.
103
+ - Python: a whole number in a tool's arguments that JavaScript cannot
104
+ hold exactly (beyond 2^53 - 1, unless a float holds it exactly) is
105
+ refused. Before, `2**60 + 1` and `2**60` left the same fingerprint in
106
+ their stubs, though the tool was handed the exact number. JSON is now
107
+ read as JavaScript reads it here too: a whole number beyond 2^53 - 1
108
+ is the nearest float.
109
+ - Python: a number of a class built on int or float (an Enum of whole
110
+ numbers, say) is written as its value, so its fingerprint is that of
111
+ the same arguments kept as JSON. Before, it was written as its name,
112
+ which is not JSON.
113
+ - A generator function is refused as a tool (`recordTools` and
114
+ `record_tools`) and by `record_function`: calling one does not run
115
+ its body, so its stub was written for an action not yet taken.
116
+ - Python: a dict in a tool's arguments whose names are not all text is
117
+ refused. Before, `{101: 2, "101": 5}` reached the tool as `{"101": 5}`.
118
+ - Python: `record_function` refuses, when it is handed the function, a
119
+ parameter whose type can never be plain data (a class of its own,
120
+ such as a model or a date, a tuple or a set), an object whose
121
+ `__call__` is defined with `async def`, and a function whose name is
122
+ not text, each in words of its own. A call whose arguments are not
123
+ plain data names the argument.
124
+ - Python: the README and the docstring say that the function is run
125
+ with a copy of its arguments, and what the record leaves out (an
126
+ argument bound into a `functools.partial` in place).
127
+ - The check before acting says "the action gives no amount", not "the
128
+ stub gives no amount". The shared file `check-before.json` now holds
129
+ a case for each of the words for a proposed action.
130
+ - Examples: `offline()` also refuses the other kinds of name look-up,
131
+ messages sent without a connection, starting another program, a
132
+ connection made by Python's event loop on Windows (which raises no
133
+ audit event), and a connection to a port on this computer that the
134
+ same program does not hold, such as a proxy's. The tests check that
135
+ nothing was refused while each example ran. Its README says exactly
136
+ what it refuses.
137
+ - 2026-10-08: examples for three widely used Python agent frameworks, in
138
+ `python/examples/`, the one folder that names them. Each records an
139
+ agent's tools with `record_function`, runs the agent with the
140
+ framework's own stand-in model (no AI service is called; tracing is
141
+ switched off; any connection outside the program is refused while it
142
+ runs), and checks the book. Each is tested
143
+ (`python/examples/test_examples.py`). The library itself still names no
144
+ product.
145
+ - 2026-10-08: the check before acting speaks of an action that is only
146
+ proposed: "With this action the total would be 280 GBP", not "With this
147
+ stub the total is", since no stub exists for an action that is not
148
+ taken. Likewise for a count and a period. The codes are unchanged; the
149
+ checker's words for a stub are unchanged.
150
+ - 2026-10-08: the Python version gains `record_function`, which puts one
151
+ ordinary function behind the stub writer and keeps its name, its
152
+ parameters and its description, so that an agent framework describes
153
+ the recorded function to its model as it would the function. Python
154
+ only: a JavaScript tool takes its arguments as one object. Tested
155
+ (`python/tests/test_record_function.py`).
156
+ - 2026-10-08: `test-vectors/README.md` says what each shared file holds
157
+ and what must match: Provared's own libraries give every answer
158
+ exactly, words included; another implementation needs to match the
159
+ codes and the shape of each answer. The Python package is made ready
160
+ for the Python Package Index (version 0.1.0, both licence files); it is
161
+ not yet published there.
162
+ - 2026-10-08: faults found by a second independent review, of the
163
+ Python stub writer and of the changes above. In 1,183 random
164
+ scenarios (about 79,500 steps) played in both languages, and 140 runs
165
+ with several threads at once, no action was taken after the person's
166
+ cancellation was handed over, and the writer's view of its book always
167
+ equalled a whole check. Each fault is fixed and each is now a test
168
+ (`python/tests/test_review2.py`).
169
+ - **An Ed25519 signature whose first half (R) is a point of small
170
+ order is refused**, in both languages, whatever the key. The holder
171
+ of an honest key could make one for any message; Node.js refused it
172
+ and the OpenSSL beneath the Python version accepted it, so one
173
+ record had two answers (format description, section 3.8).
174
+ - A copy of what the stub writer is handed is refused if it nests more
175
+ than 64 levels deep, in both languages. Before, the JavaScript
176
+ library's limit depended on how much of the stack was in use. The
177
+ depth is measured on the copy, so the caller's value is still read
178
+ once.
179
+ - Python: a cancellation handed to `add` beside a member whose name is
180
+ a number, None or something stranger, or in a read-only mapping, is
181
+ read, and stops the writer, as in JavaScript. An error from the other
182
+ side that is not an `Exception` (such as `SystemExit`) leaves a
183
+ one-sided stub, as any other failure does. `snapshot()` hands back
184
+ the book and the cancellations the writer holds, read together, so
185
+ that another thread's call cannot fall between the two. A number too
186
+ large for a float is no time; options holding objects that cannot be
187
+ copied are kept as they are, as the JavaScript library keeps them;
188
+ the record writers take a datetime with a time zone, as the
189
+ JavaScript ones take a Date.
190
+ - 2026-10-08: faults found by an independent review of the Python
191
+ version, which also changed the JavaScript library.
192
+ - **Weak Ed25519 keys are refused.** Under one of the eight Ed25519
193
+ keys of small order, anyone can make a signature that checks.
194
+ Node.js refused such signatures; the OpenSSL beneath the Python
195
+ version accepted them, so with such a key trusted, a slip made by
196
+ someone holding no private key read as sound there. RFC 8032 does
197
+ not say to refuse these keys and libraries differ, so now the
198
+ checker refuses them itself, with any key written in more than one
199
+ way (y not below p): `bad-key` for a key in a record,
200
+ `stamp-invalid` for a time-stamp service's key.
201
+ - **The page address in a slip follows an exact rule.** The checker
202
+ used the URL Standard's own reader of addresses, which for a name
203
+ beginning `xn--` rests on tables of Unicode that differ from one
204
+ version of Node.js to the next, so two checkers could disagree. Now
205
+ `issuer.origin` must be written as a browser writes it, by a rule
206
+ that needs no such tables: `https://` (or `http://localhost`), a
207
+ host of lower-case letters, digits and hyphens in labels, a port
208
+ only where it is not the scheme's own, and nothing more (format
209
+ description, section 4.1). Some addresses the URL Standard allows
210
+ are now refused: underscores and other signs in a host, port 0,
211
+ addresses of numbers.
212
+ - A time-stamp service's key of another kind, or on another curve, is
213
+ refused in words that say so, not as a signature that "does not
214
+ fit".
215
+ - A time is read only from a number of milliseconds or a Date. Text,
216
+ true or a list were read by rules that differ from one device to
217
+ another (text with no time zone was taken as local time).
218
+ - `withoutMethods` that is not a list is set aside when a slip is
219
+ checked, as everywhere else. Before, it made the slip's check fail.
220
+ - 2026-10-08: the Python version gains the stub writer beside an agent
221
+ (`open_recorder`) and the connector for an agent's tools
222
+ (`record_tools`, `arguments_fingerprint`, `NotTaken`). So it now does
223
+ everything the JavaScript library does.
224
+ - They are ported one to one and give the same answers: two new
225
+ shared files, `test-vectors/recorder-scenarios.json` (32 scenarios,
226
+ about 1,000 steps) and `test-vectors/tool-scenarios.json` (8
227
+ scenarios), each a world of records made beforehand and a list of
228
+ steps (actions, records, cancellations in every form the writer
229
+ takes, time-stamps, acknowledgements, a clock that fails, writers
230
+ opened again, tools called), with the transcript of what happened.
231
+ The two libraries play each scenario (`test/helpers/scenarios.mjs`
232
+ and `python/tests/scenarios.py`) and must write the same transcript,
233
+ down to the words of every message and how many times the clock was
234
+ read.
235
+ - In Python every call is an ordinary function. The writer's calls
236
+ wait for one another across threads. A call to the writer from
237
+ inside an action it is taking, or from the other side while it
238
+ countersigns, is refused at once, as in Node.js. The other side is
239
+ asked in a thread of its own and given 30 seconds, as before. A
240
+ function handed over that gives a coroutine is refused.
241
+ - `key_set_from_seeds` and `key_set_seeds`: an agent's keys kept
242
+ between runs as their two 32-byte seeds.
243
+ - The Python reading of base64url and the copy of a check's options
244
+ are faster; they give the same answers (a value shared many times in
245
+ the options is now copied once, as the JavaScript library copies it).
246
+ - `test/helpers/world.mjs` can be given the agent's and the service's
247
+ key sets, so that a scenario can hand the same keys to Python.
248
+ - 2026-10-08: two faults in the check of a time-stamp from a service,
249
+ found while writing the Python version.
250
+ - An RSA key with the public number 1 in a service's certificate was
251
+ accepted. Under it, anyone can make a signature that checks, so a
252
+ time-stamp could be made without the service's private key. It
253
+ counted only where the person checking had named that certificate as
254
+ trusted. An even public number was accepted too. Now the public
255
+ number must be odd, from 3 to 2^32 - 1 (`stamp-invalid`).
256
+ - The public key inside a certificate was read loosely: a compressed or
257
+ "hybrid" point, RSA numbers with needless or missing sign bytes,
258
+ bytes after the key, any parameters, and unused bits all loaded. Now
259
+ the key must be written exactly as its own standard sets out
260
+ (`stamp-bad-data`), as the rest of a time-stamp already must be, so
261
+ that two checkers cannot disagree about whether it can be read.
262
+ - Each is a shared test (`test-vectors/stamps-strict-keys.json`).
263
+ - 2026-10-08: shared test files, and the start of a Python version.
264
+ - `test-vectors/` holds records and values, each with the answer this
265
+ library gives: the canonical form, base64url, times, keys, a
266
+ passkey's signature, the envelope of a record, the content of a stub
267
+ and of a countersignature, page addresses and 170 slips, sound and
268
+ faulty. `tools/make-vectors.mjs` writes them;
269
+ `test/vectors.test.mjs` checks that this library still gives every
270
+ answer. Any other implementation of the format can be tested against
271
+ them.
272
+ - `python/` holds a Python version, built in stages against the same
273
+ files. It is not yet published. It now checks everything the
274
+ JavaScript library checks: slips, stubs, countersignatures, limits,
275
+ approvals, refusals and terms, passes, cancellations and
276
+ acknowledgements, vouching records, seals and their time-stamps,
277
+ block time-stamps, the tree and its proofs, Shows, the chain of
278
+ block headers, and the check before acting. It gives the same answer
279
+ in every one of the 63 shared files, and in 6,091 random books
280
+ compared on this computer. One difference is stated: "cryptography",
281
+ the one package it needs, has no SLH-DSA yet, so a seal's third
282
+ signature is reported as not checked on this device and never as a
283
+ pass. The stub writer and the connector for an agent's tools are
284
+ still to come.
285
+ - A slip whose page address cannot be read, and one whose address is
286
+ not in its plain form, are now refused with the same words. The code
287
+ (`bad-field`) is unchanged.
288
+ - 2026-10-07: the README links to the individual Internet-Draft
289
+ `draft-izmaylov-agent-permission-receipts`, which describes the core of
290
+ the format.
291
+
292
+ ## 0.1.0 (6 October 2026)
293
+
294
+ Draft version 0 of the format, published and not frozen.
6
295
 
7
296
  - 2026-10-05: `provared-headers` is marked as experimental, in the
8
297
  README and in what the command prints.