@factoidal/core 0.7.0 → 0.10.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.
Files changed (193) hide show
  1. package/CHANGELOG.md +510 -1
  2. package/NOTICE +2 -21
  3. package/README.md +117 -993
  4. package/api.d.ts +53 -0
  5. package/api.js +5 -0
  6. package/api.mjs +56 -0
  7. package/bin/engine.mjs +38 -19
  8. package/bin/factoidal.mjs +513 -67
  9. package/bin/pack.mjs +37 -0
  10. package/bin/serve-worker.mjs +32 -0
  11. package/bin/serve.mjs +423 -0
  12. package/bin/store-worker-host.mjs +1 -1
  13. package/bin/store.mjs +1 -1
  14. package/browser.d.ts +110 -507
  15. package/browser.js +151 -2257
  16. package/docs/fuseki-replacement.md +108 -0
  17. package/fn.d.ts +24 -95
  18. package/fn.js +104 -150
  19. package/index.d.ts +598 -259
  20. package/index.js +4 -234
  21. package/index.mjs +176 -84
  22. package/l4-assets/l4factoidal.js +47 -7
  23. package/l4-assets/l4factoidal.mjs +1 -1
  24. package/l4-assets/l4factoidal.wasm +0 -0
  25. package/l4-assets/version.json +11 -7
  26. package/lib/api.mjs +2300 -0
  27. package/lib/browser-engine.mjs +69 -0
  28. package/lib/dataset.mjs +377 -0
  29. package/lib/delta-log-hosts.mjs +191 -0
  30. package/lib/lean-entry.mjs +204 -0
  31. package/lib/pure.mjs +98 -0
  32. package/lib/store.mjs +115 -0
  33. package/lib/version.mjs +5 -0
  34. package/lws/README.md +97 -0
  35. package/lws/server.mjs +331 -0
  36. package/package.json +59 -61
  37. package/rdfjs.js +5 -536
  38. package/rdfjs.mjs +594 -0
  39. package/sample-store.d.ts +8 -16
  40. package/sample-store.mjs +39 -29
  41. package/solid/client/README.md +100 -0
  42. package/solid/client/index.mjs +277 -0
  43. package/solid/server/README.md +96 -0
  44. package/solid/server/index.mjs +317 -0
  45. package/store-host/deno.mjs +8 -0
  46. package/store-host/index.mjs +12 -0
  47. package/store-host/node.mjs +8 -0
  48. package/xmpp/README.md +107 -0
  49. package/xmpp/index.mjs +229 -0
  50. package/browser-wasm.js +0 -872
  51. package/factoidal-npm-entry.js +0 -15477
  52. package/factoidal-npm-entry.wasm.assets/code-5a7fc68f2ab1323718b8.wasm +0 -0
  53. package/factoidal-npm-entry.wasm.js +0 -455
  54. package/factoidal.js +0 -13118
  55. package/factoidal.wasm.assets/code-bbe6099bfb5b10c4c3ab.wasm +0 -0
  56. package/factoidal.wasm.js +0 -457
  57. package/hacl-init.js +0 -92
  58. package/hacl-wasm/FStar.wasm +0 -0
  59. package/hacl-wasm/Hacl_Bignum.wasm +0 -0
  60. package/hacl-wasm/Hacl_Bignum25519_51.wasm +0 -0
  61. package/hacl-wasm/Hacl_Bignum_Base.wasm +0 -0
  62. package/hacl-wasm/Hacl_Curve25519_51.wasm +0 -0
  63. package/hacl-wasm/Hacl_Ed25519.wasm +0 -0
  64. package/hacl-wasm/Hacl_Ed25519_PrecompTable.wasm +0 -0
  65. package/hacl-wasm/Hacl_Hash_Base.wasm +0 -0
  66. package/hacl-wasm/Hacl_Hash_SHA2.wasm +0 -0
  67. package/hacl-wasm/Hacl_IntTypes_Intrinsics.wasm +0 -0
  68. package/hacl-wasm/LowStar_Endianness.wasm +0 -0
  69. package/hacl-wasm/WasmSupport.wasm +0 -0
  70. package/hacl-wasm/api.js +0 -775
  71. package/hacl-wasm/api.json +0 -3787
  72. package/hacl-wasm/layouts.json +0 -1
  73. package/hacl-wasm/loader.js +0 -568
  74. package/hacl-wasm/shell.js +0 -12
  75. package/l4-core.d.ts +0 -159
  76. package/l4-core.js +0 -188
  77. package/l4.d.ts +0 -50
  78. package/l4.js +0 -104
  79. package/lib/api.js +0 -2300
  80. package/lib/engine-js.js +0 -165
  81. package/lib/engine-wasm.js +0 -300
  82. package/sample-store/CURRENT +0 -1
  83. package/sample-store/gen-1/manifest.sbm2 +0 -0
  84. package/sample-store/gen-1/manifest.tsv +0 -14
  85. package/sample-store/gen-1/predicate-0.ibk3 +0 -0
  86. package/sample-store/gen-1/predicate-0.ibk3.merkle +0 -1
  87. package/sample-store/gen-1/predicate-0.ibk3.oli2 +0 -0
  88. package/sample-store/gen-1/predicate-0.ibk3.oli2.merkle +0 -1
  89. package/sample-store/gen-1/predicate-0.ibk3.sri2 +0 -0
  90. package/sample-store/gen-1/predicate-0.ibk3.sri2.merkle +0 -1
  91. package/sample-store/gen-1/predicate-0.ibk3.tli1 +0 -0
  92. package/sample-store/gen-1/predicate-0.ibk3.tli1.merkle +0 -0
  93. package/sample-store/gen-1/predicate-1.ibk3 +0 -0
  94. package/sample-store/gen-1/predicate-1.ibk3.merkle +0 -0
  95. package/sample-store/gen-1/predicate-1.ibk3.oli2 +0 -0
  96. package/sample-store/gen-1/predicate-1.ibk3.oli2.merkle +0 -0
  97. package/sample-store/gen-1/predicate-1.ibk3.sri2 +0 -0
  98. package/sample-store/gen-1/predicate-1.ibk3.sri2.merkle +0 -1
  99. package/sample-store/gen-1/predicate-1.ibk3.tli1 +0 -0
  100. package/sample-store/gen-1/predicate-1.ibk3.tli1.merkle +0 -1
  101. package/sample-store/gen-1/predicate-10.ibk3 +0 -0
  102. package/sample-store/gen-1/predicate-10.ibk3.merkle +0 -1
  103. package/sample-store/gen-1/predicate-10.ibk3.oli2 +0 -0
  104. package/sample-store/gen-1/predicate-10.ibk3.oli2.merkle +0 -0
  105. package/sample-store/gen-1/predicate-10.ibk3.sri2 +0 -0
  106. package/sample-store/gen-1/predicate-10.ibk3.sri2.merkle +0 -1
  107. package/sample-store/gen-1/predicate-10.ibk3.tli1 +0 -0
  108. package/sample-store/gen-1/predicate-10.ibk3.tli1.merkle +0 -1
  109. package/sample-store/gen-1/predicate-11.ibk3 +0 -0
  110. package/sample-store/gen-1/predicate-11.ibk3.merkle +0 -0
  111. package/sample-store/gen-1/predicate-11.ibk3.oli2 +0 -0
  112. package/sample-store/gen-1/predicate-11.ibk3.oli2.merkle +0 -1
  113. package/sample-store/gen-1/predicate-11.ibk3.sri2 +0 -0
  114. package/sample-store/gen-1/predicate-11.ibk3.sri2.merkle +0 -1
  115. package/sample-store/gen-1/predicate-11.ibk3.tli1 +0 -0
  116. package/sample-store/gen-1/predicate-11.ibk3.tli1.merkle +0 -1
  117. package/sample-store/gen-1/predicate-12.ibk3 +0 -0
  118. package/sample-store/gen-1/predicate-12.ibk3.merkle +0 -1
  119. package/sample-store/gen-1/predicate-12.ibk3.oli2 +0 -0
  120. package/sample-store/gen-1/predicate-12.ibk3.oli2.merkle +0 -1
  121. package/sample-store/gen-1/predicate-12.ibk3.sri2 +0 -0
  122. package/sample-store/gen-1/predicate-12.ibk3.sri2.merkle +0 -1
  123. package/sample-store/gen-1/predicate-12.ibk3.tli1 +0 -0
  124. package/sample-store/gen-1/predicate-12.ibk3.tli1.merkle +0 -1
  125. package/sample-store/gen-1/predicate-2.ibk3 +0 -0
  126. package/sample-store/gen-1/predicate-2.ibk3.merkle +0 -1
  127. package/sample-store/gen-1/predicate-2.ibk3.oli2 +0 -0
  128. package/sample-store/gen-1/predicate-2.ibk3.oli2.merkle +0 -1
  129. package/sample-store/gen-1/predicate-2.ibk3.sri2 +0 -0
  130. package/sample-store/gen-1/predicate-2.ibk3.sri2.merkle +0 -0
  131. package/sample-store/gen-1/predicate-2.ibk3.tli1 +0 -0
  132. package/sample-store/gen-1/predicate-2.ibk3.tli1.merkle +0 -0
  133. package/sample-store/gen-1/predicate-3.ibk3 +0 -0
  134. package/sample-store/gen-1/predicate-3.ibk3.merkle +0 -1
  135. package/sample-store/gen-1/predicate-3.ibk3.oli2 +0 -0
  136. package/sample-store/gen-1/predicate-3.ibk3.oli2.merkle +0 -1
  137. package/sample-store/gen-1/predicate-3.ibk3.sri2 +0 -0
  138. package/sample-store/gen-1/predicate-3.ibk3.sri2.merkle +0 -1
  139. package/sample-store/gen-1/predicate-3.ibk3.tli1 +0 -0
  140. package/sample-store/gen-1/predicate-3.ibk3.tli1.merkle +0 -1
  141. package/sample-store/gen-1/predicate-4.ibk3 +0 -0
  142. package/sample-store/gen-1/predicate-4.ibk3.merkle +0 -0
  143. package/sample-store/gen-1/predicate-4.ibk3.oli2 +0 -0
  144. package/sample-store/gen-1/predicate-4.ibk3.oli2.merkle +0 -1
  145. package/sample-store/gen-1/predicate-4.ibk3.sri2 +0 -0
  146. package/sample-store/gen-1/predicate-4.ibk3.sri2.merkle +0 -1
  147. package/sample-store/gen-1/predicate-4.ibk3.tli1 +0 -0
  148. package/sample-store/gen-1/predicate-4.ibk3.tli1.merkle +0 -2
  149. package/sample-store/gen-1/predicate-5.ibk3 +0 -0
  150. package/sample-store/gen-1/predicate-5.ibk3.merkle +0 -1
  151. package/sample-store/gen-1/predicate-5.ibk3.oli2 +0 -0
  152. package/sample-store/gen-1/predicate-5.ibk3.oli2.merkle +0 -1
  153. package/sample-store/gen-1/predicate-5.ibk3.sri2 +0 -0
  154. package/sample-store/gen-1/predicate-5.ibk3.sri2.merkle +0 -1
  155. package/sample-store/gen-1/predicate-5.ibk3.tli1 +0 -0
  156. package/sample-store/gen-1/predicate-5.ibk3.tli1.merkle +0 -1
  157. package/sample-store/gen-1/predicate-6.ibk3 +0 -0
  158. package/sample-store/gen-1/predicate-6.ibk3.merkle +0 -1
  159. package/sample-store/gen-1/predicate-6.ibk3.oli2 +0 -0
  160. package/sample-store/gen-1/predicate-6.ibk3.oli2.merkle +0 -1
  161. package/sample-store/gen-1/predicate-6.ibk3.sri2 +0 -0
  162. package/sample-store/gen-1/predicate-6.ibk3.sri2.merkle +0 -1
  163. package/sample-store/gen-1/predicate-6.ibk3.tli1 +0 -0
  164. package/sample-store/gen-1/predicate-6.ibk3.tli1.merkle +0 -0
  165. package/sample-store/gen-1/predicate-7.ibk3 +0 -0
  166. package/sample-store/gen-1/predicate-7.ibk3.merkle +0 -0
  167. package/sample-store/gen-1/predicate-7.ibk3.oli2 +0 -0
  168. package/sample-store/gen-1/predicate-7.ibk3.oli2.merkle +0 -2
  169. package/sample-store/gen-1/predicate-7.ibk3.sri2 +0 -0
  170. package/sample-store/gen-1/predicate-7.ibk3.sri2.merkle +0 -1
  171. package/sample-store/gen-1/predicate-7.ibk3.tli1 +0 -0
  172. package/sample-store/gen-1/predicate-7.ibk3.tli1.merkle +0 -1
  173. package/sample-store/gen-1/predicate-8.ibk3 +0 -0
  174. package/sample-store/gen-1/predicate-8.ibk3.merkle +0 -1
  175. package/sample-store/gen-1/predicate-8.ibk3.oli2 +0 -0
  176. package/sample-store/gen-1/predicate-8.ibk3.oli2.merkle +0 -1
  177. package/sample-store/gen-1/predicate-8.ibk3.sri2 +0 -0
  178. package/sample-store/gen-1/predicate-8.ibk3.sri2.merkle +0 -1
  179. package/sample-store/gen-1/predicate-8.ibk3.tli1 +0 -0
  180. package/sample-store/gen-1/predicate-8.ibk3.tli1.merkle +0 -1
  181. package/sample-store/gen-1/predicate-9.ibk3 +0 -0
  182. package/sample-store/gen-1/predicate-9.ibk3.merkle +0 -1
  183. package/sample-store/gen-1/predicate-9.ibk3.oli2 +0 -0
  184. package/sample-store/gen-1/predicate-9.ibk3.oli2.merkle +0 -1
  185. package/sample-store/gen-1/predicate-9.ibk3.sri2 +0 -0
  186. package/sample-store/gen-1/predicate-9.ibk3.sri2.merkle +0 -3
  187. package/sample-store/gen-1/predicate-9.ibk3.tli1 +0 -0
  188. package/sample-store/gen-1/predicate-9.ibk3.tli1.merkle +0 -2
  189. package/select.d.ts +0 -116
  190. package/select.js +0 -492
  191. package/version.json +0 -102
  192. package/wasm.d.ts +0 -130
  193. package/wasm.js +0 -158
package/CHANGELOG.md CHANGED
@@ -1,5 +1,514 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.10.0 (unreleased)
4
+
5
+ ### Breaking changes
6
+
7
+ One wasm carries every capability (owner, 2026-10-20: "all this stuff goes
8
+ into a single mod we call Factoidal/core and a dingle wasm"):
9
+
10
+ - The duplicate smaller wasm (`l4-assets/l4factoidal-core.{wasm,mjs,js}`) and
11
+ its `./core` and `./core-browser` subpaths are gone. `l4factoidal.wasm`
12
+ serves every function of the package; import `@factoidal/core`.
13
+ `l4-assets/version.json` has no `coreWasmSha256`/`coreWasmBytes`.
14
+ - No demonstration triples ship (owner: "All the CLIs are still bundled i
15
+ just didn't want any actual demo triples cluttering the file"): the
16
+ 4,434-triple `sample-store/` directory is gone. `factoidal sample-store
17
+ [DIR]` and `sampleStorePath([dir])` now pack 15 triples held in
18
+ `sample-store.mjs` into a store under DIR or the temporary directory and
19
+ return its path; `sampleStoreFacts` describes that store.
20
+ - The demonstration functions `matrixDeterminant`, `matrixScalarProduct`,
21
+ `matrixVectorProduct`, `matrixOuterProduct`, `sigmoidPoints` and
22
+ `sigmoidFormulaMathml` (and `capabilities().matrix`/`.sigmoid`) left the
23
+ JavaScript API, `@factoidal/core/fn` and the types. The Lean ops stay and
24
+ answer through `loadEngine().call(op, args)`.
25
+
26
+ One `Dataset` class whose data stays in the engine
27
+ (https://github.com/danbri/factoidal/issues/882 item 1):
28
+
29
+ - `Dataset` is a handle into the engine's dataset store; it no longer holds
30
+ N-Quads text. `new Dataset(...)` and `Dataset.fromNQuads(...)` are gone:
31
+ make one with `parse`, `openDataset` or another producer. It still implements RDF/JS DatasetCore:
32
+ `add`, `delete`, `has` and `match` run in the engine (`match` and `has` use
33
+ its indexes; `match` answers a new Dataset). The in-memory RDF/JS DatasetCore is
34
+ `DatasetCore` in `@factoidal/core/rdfjs` (that subpath no longer exports
35
+ `Dataset`).
36
+ - `DatasetHandle` is a deprecated alias of `Dataset` (removed in 0.11.0).
37
+ `handle.close()`, `handle.closed` and `handle.toDataset()` are replaced by
38
+ `dispose()`, `disposed` and the Dataset itself. Using a disposed Dataset
39
+ throws a `TypeError`.
40
+ - `openDataset` answers a `Dataset` (a Dataset argument is cloned).
41
+ - `coreRdfsClosure`/`rhoDfClosure` and `rdfsPlusClosure` answer a `Dataset`
42
+ (before: `{ok, ntriples}` and `{ok, ntriples, rounds}`; `rounds` is gone).
43
+ `fn.coreRdfsClosure` and `fn.rdfsPlusClosure` drop `rounds` too.
44
+ - Text input with no `format` is no longer read as Turtle: the engine infers
45
+ the format (op `detectFormat`: JSON-LD, RDF/XML, TriG or Turtle, in RDF
46
+ 1.2 mode) and reports it in `dataset.format` / `dataset.formatInferred`, or
47
+ in the error message. N-Quads is never inferred; name it.
48
+ - Every function throws a `TypeError` for an unknown option key.
49
+ - `update(dataset, text)` answers a new Dataset and leaves its argument
50
+ unchanged (as before); `dataset.update(text)` changes it in place.
51
+ - `fn.toDataset` answers a DatasetCore; `fn.fromDataset` takes a `Dataset`
52
+ or a DatasetCore.
53
+
54
+ ### New
55
+
56
+ - `Dataset` methods: `query` (with `entail` and `output`: SPARQL results
57
+ JSON, XML, CSV, TSV), `update`, `validateShacl`, `validateShex`,
58
+ `closure(regime)`, `canonicalize`, `serialize({format, version})`,
59
+ `toString(format)`, `clone`, `has`, `match`, lazy RDF/JS quad iteration,
60
+ `dispose`, `[Symbol.dispose]`; a `FinalizationRegistry` releases a
61
+ collected Dataset.
62
+ - `serialize` writes every writer the engine has: N-Quads, N-Triples,
63
+ Turtle, TriG, RDF/XML, JSON-LD, RDFC-1.0 canonical N-Quads, each with
64
+ `version: '1.1'` (refuses RDF 1.2 terms) or `'1.2'`. `formats()` gives the
65
+ engine's list; the README table is generated from it. Writers the engine
66
+ lacks: https://github.com/danbri/factoidal/issues/883.
67
+ - `closure(data, regime)`.
68
+ - Engine ops (Lean, `Wasm/Ops/Handles.lean`, `Wasm/Ops/DatasetFull.lean`):
69
+ `datasetClone`, `datasetCanonicalize`, `datasetClosure`,
70
+ `datasetShaclValidate`, `datasetQueryRaw`, `datasetFormats`,
71
+ `detectFormat`, `datasetFromCsvw`, `datasetFromRml`, `datasetFromJsonLd`,
72
+ `datasetToJsonLd`, `datasetShexValidate`, `datasetRifEval`; and
73
+ `datasetSerialize` writes N-Triples, TriG, RDF/XML and RDFC-1.0.
74
+ - Every example in README.md and API.md is executed by
75
+ `test/doc-examples.test.mjs`.
76
+
77
+ ### Other changes
78
+
79
+ - The README is a short summary: what the package is, a usage example, the
80
+ JavaScript API and command list, the specifications covered with test
81
+ scores and their sources, and measured strengths and gaps. The previous
82
+ README is `API.md` in the repository (not in the tarball).
83
+ - New pure functions over engine ops that had no JavaScript function:
84
+ `aeadSeal`, `aeadOpen` (ChaCha20-Poly1305, RFC 8439), `hpkeSeal`,
85
+ `hpkeOpen` (RFC 9180 base mode), `proofCheck`, `proofInspect` (FPP0 proof
86
+ bundles), `canonicalizeNQuads` and `normalizeNQuads` (N-Quads text in, text
87
+ out). Tests: `test/pure-and-serve.test.mjs`.
88
+ - New `serveStore(root, {port, host})`: the `factoidal serve` SPARQL 1.1
89
+ Protocol server as a function, `{url, port, close()}`. Node only.
90
+ - `factoidal serve --file DATA /ds`, the `fuseki-server --file` form, and
91
+ the Fuseki service names `/ds/query`, `/ds/update` and `/ds/get` beside
92
+ `/ds/sparql` (decided in `StoreEndpoint.lean`). Record and gaps:
93
+ `docs/fuseki-replacement.md`; tests `test/fuseki-compat.test.mjs`. W3C live
94
+ protocol run: 50 pass, 0 fail (out of 50).
95
+ - The wasm is rebuilt from `main`; the package carries the Lean 4 engine only.
96
+ Package suite: 432 pass, 0 fail (out of 432); 4 of them are expected
97
+ failures naming issues 829, 830 and 831.
98
+ - Removed: the 0.9.x subpath aliases `@factoidal/core/l4` and
99
+ `@factoidal/core/l4-core` (files `l4.js`, `l4.d.ts`, `l4-core.js`,
100
+ `l4-core.d.ts`), as announced in 0.9.0. Import `@factoidal/core`; the
101
+ low-level engine handle is `loadEngine()`.
102
+ - `l4-assets/version.json` is written at release from the
103
+ `danbri/factoidal-builds` release that built the wasm
104
+ (`tools/fetch-builds.sh --set web`): source commit, build time, sha256 and
105
+ size of both wasm files, and the engine's own version. The committed file
106
+ is a placeholder. `factoidal version` prints the stamp and the loaded
107
+ engine's `version()`, and exits 1 when the stamped sha256 differs from the
108
+ installed wasm.
109
+ - RDF 1.2 format tags `turtle12`, `ntriples12`, `nquads12`, `trig12` are in
110
+ the `DataFormat` type.
111
+ - Includes the entries listed under "Unreleased" below.
112
+
113
+ ## Unreleased (included in 0.10.0)
114
+
115
+ - **The durable update log in the browser, on the Lean engine**
116
+ ([issue 728](https://github.com/danbri/factoidal/issues/728); hub post 18).
117
+ `deltaLogOpen`, `deltaLogAppend`, `deltaLogReadAllHex`, `deltaLogMerge`,
118
+ `deltaLogDestroy` and `_deltaLogCorruptLastForTest` are back, with the names
119
+ and result shapes of the F\* browser entry before 0.9.0, and
120
+ `deltaLogInspect` and the capability `deltaLog` are new. One record per
121
+ update, in the DLB1 format of the store's delta log; the engine ops
122
+ `deltaLogEncode`, `deltaLogDecode` and `deltaLogMerge` make every decision
123
+ about the bytes (checksums, a torn last record, merge on read), with
124
+ theorems in `formal/lean4/L4Factoidal/Storage/BrowserLogTheorems.lean`.
125
+ The browser entries keep the records in IndexedDB; the Node entries keep
126
+ them in the memory of the process. A record that does not verify, and
127
+ every record after it, is not applied.
128
+
129
+ - **SPARQL `SERVICE` failures inside `EXISTS` and under an outer `SILENT`**
130
+ ([issue 735](https://github.com/danbri/factoidal/issues/735); SPARQL 1.1
131
+ Federated Query §2.3 and §3.2). A failed `SERVICE` call without `SILENT`
132
+ inside `EXISTS` or `NOT EXISTS` (in `FILTER`, `BIND`, an `OPTIONAL`
133
+ condition, `HAVING`, `ORDER BY` or a `SELECT` expression) now fails the
134
+ query, as the same call in a graph pattern does. A failed `SERVICE` call
135
+ nested in the body of an outer `SERVICE SILENT` is a failure of the outer
136
+ call, so the outer call gives one solution with no bindings; without
137
+ `SILENT` on the outer call the query fails. The two expected-failure cases
138
+ in `test/l4-parity.test.js` are now assertions.
139
+
140
+ - **`factoidal serve STORE --port N`: a SPARQL 1.1 endpoint over an activated
141
+ store** ([issue 669](https://github.com/danbri/factoidal/issues/669), step
142
+ 1). SPARQL 1.1 Protocol query and update at `/sparql`, the Service
143
+ Description on a GET there with no query string, and the Graph Store HTTP
144
+ Protocol at `/data`. An update or a Graph Store write is appended to the
145
+ generation's delta log as one batch, synced, before it is answered. The
146
+ request framing, routing, status codes, negotiation and the delta-log batch
147
+ are decided by the engine (`storeServeKeys`, `storeServeOpen`,
148
+ `storeServeRequest`, `storeServeCommit`, `storeServeClose`); `bin/serve.mjs`
149
+ moves bytes. W3C protocol, graph-store and service-description tests over
150
+ a live socket: 50 pass, 0 fail (out of 50). Open gap: a quad generation's
151
+ delta log is not replayed by the native quad reader
152
+ ([issue 770](https://github.com/danbri/factoidal/issues/770)).
153
+ - **`@factoidal/core/core`: the core engine** ([issue 713](https://github.com/danbri/factoidal/issues/713),
154
+ stage 4). `l4factoidal-core.wasm` (5.68 MB, 1.07 MB with gzip; the full
155
+ engine is 10.54 MB, 2.07 MB) serves parse and serialize (Turtle, TriG,
156
+ N-Triples, N-Quads, RDF/XML, lenient), SPARQL 1.1 and 1.2 query and update
157
+ over text and dataset handles, canonicalization, the RDFS and OWL 2 RL
158
+ closures and SHACL. The entry has the same exports as `.`; a function
159
+ outside that subset rejects naming `@factoidal/core`, and
160
+ `capabilities().profile` is `'core'` (`'full'` on the other entries).
161
+ Files: `core.mjs`, `core.js`, `core-browser.js`, `core.d.ts`,
162
+ `core-browser.d.ts`, `l4-assets/l4factoidal-core.{js,mjs,wasm}`.
163
+ - A SELECT of more than about 11,000 solutions, and `canonicalize()` of more
164
+ than about 20,000 blank-node quads, no longer fail under Node's default
165
+ stack with "Maximum call stack size exceeded". Four functions of the Lean
166
+ library recursed once per row or per quad (`SPARQL.numberRows`,
167
+ `SPARQL.rowsJoined`, `RDF.Canonical.collapseKeyedQQuads`, `dedupAdj`);
168
+ each now compiles to an accumulator form proved equal to it. The Results
169
+ JSON writer had also copied the rest of the document once per row.
170
+ - `NOW()` is bound ([issue 743](https://github.com/danbri/factoidal/issues/743)).
171
+ Through `query()`, `update()`, dataset handles, the entailment path,
172
+ `queryHdt()` and the store queries, SPARQL `NOW()` answered an error and left
173
+ its variable unbound (W3C `functions/now01.rq` answered `false`). The engine
174
+ now reads the system clock once per query or update and gives every `NOW()` of
175
+ that execution the same `xsd:dateTime` value in UTC (SPARQL 1.1 §17.4.5.1).
176
+ The wasm modules grow by about 82 KB (full) and 89 KB (core).
177
+ - The pure dispatch entries take the instant of `NOW()` as an optional last
178
+ argument ([issue 748](https://github.com/danbri/factoidal/issues/748)).
179
+ `call` and `callBlob` read no clock, so a host that uses them got an error
180
+ for `NOW()`. `queryDataset` and `updateDataset` (fourth, after the base IRI),
181
+ `queryRaw` and `storeQuery` (fourth) and `queryHdt` (second) now accept an
182
+ `xsd:dateTime` lexical form such as `2026-10-10T12:34:56Z`; an empty string
183
+ means none, and a text that is not a dateTime lexical form is an error. Hosts
184
+ that pass fewer arguments do not change. `callIO` and `callBlobIO` still read
185
+ the clock themselves.
186
+ - `Dataset` (`./rdfjs`) adds and looks up a quad in constant time. It
187
+ scanned every quad it held, so `parse()` of 12,000 quads spent 3.1 s
188
+ building the result; it now takes 0.35 s.
189
+
190
+ ## 0.9.0 — 2026-10-10
191
+
192
+ **One engine: the Lean 4 build.** ([issue 713](https://github.com/danbri/factoidal/issues/713),
193
+ stage 3.) Owner, 2026-10-10: "We should make the main module Lean4-based.
194
+ Private builds might compare this with F\* (or indeed different wasms from
195
+ different toolchains)." The main entry (`.`: `index.js`, `index.mjs`),
196
+ `./api`, `./fn` and `./browser` now load the Lean 4 library `L4Factoidal`
197
+ compiled to WebAssembly (`l4-assets/`). Every function is a dispatch op of
198
+ that module behind the typed wrapper the F\* engine had, with the same
199
+ signatures and result shapes except where the list below says otherwise.
200
+
201
+ Removed, with no replacement shim (there are no users):
202
+
203
+ - the F\* bundles (`factoidal.js`, `factoidal.wasm.js`,
204
+ `factoidal-npm-entry*.js` and their wasm assets) and the entry points
205
+ that loaded them: `./wasm`, `./lite`, `./browser-wasm`, `./select`, and the
206
+ `./factoidal*.js` subpaths. The F\* bundles stay build artifacts of
207
+ `danbri/factoidal-builds`, for private comparison builds:
208
+ `tests/engine-compare/run.sh PATH/TO/factoidal-npm-entry.js`.
209
+ - `hacl-wasm/` and `hacl-init.js`: Ed25519 is HACL\*'s C code compiled into
210
+ the Lean wasm module, SHA-256 is the Lean hash, and there is no
211
+ initialisation step.
212
+ - the COTTAS functions `openCottas`, `queryCottas`, `closeCottas` and
213
+ `toCottas` (on the main entry and on `./fn`), and the browser delta log
214
+ (`deltaLogOpen` ... `deltaLogDestroy`), which wrote COTTAS batches. The
215
+ owner ruled the F\* COTTAS store essentially unused
216
+ ([issue 566](https://github.com/danbri/factoidal/issues/566)). The
217
+ Lean persisted store replaces them (below); its update path in JavaScript
218
+ is [issue 641](https://github.com/danbri/factoidal/issues/641).
219
+ - the F\* `version.json` with its claims block. `l4-assets/version.json` is
220
+ the engine's provenance.
221
+
222
+ New:
223
+
224
+ - **The persisted store on the main entry**: `openStore(source, options)`
225
+ answers a `Store` (a store handle inside the engine: every artifact
226
+ verified against its manifest's SHA-256 once, then queried from the
227
+ retained blocks), `queryStore(source, sparql)`, `listStores()`, and
228
+ `sampleStorePath()` / `sampleStoreFacts`. `source` is a collection root
229
+ path (Node) or a reader function `(path) => bytes`, which is how a page
230
+ reads a store over `fetch()`.
231
+ - `shaclValidate` and `shexValidate` on the Lean engine (ops of
232
+ `formal/lean4/Wasm/Ops/Validate.lean`): SHACL Core, SHACL-SPARQL and SHACL
233
+ 1.2 node expressions; ShExJ or ShExC schemas. `shexValidate` answers a
234
+ boolean (the F\* engine answered `null` outside its decidable fragment).
235
+ - SPARQL 1.2 queries: `query(data, q, {sparql12: true})` and
236
+ `handle.query(q, {sparql12: true})` (ops `queryDataset12`,
237
+ `datasetQuery12`): triple-term patterns, reified triples, annotations,
238
+ `TRIPLE`/`isTRIPLE`/`SUBJECT`/`PREDICATE`/`OBJECT`.
239
+ - `query(data, q, {entail})` with `RDFS`, `OWL-RL`, `x-rdfscore` or
240
+ `x-rdfsplus` runs in the engine (op `queryRaw`): the default graph is
241
+ closed under the regime, then the query is answered. SELECT, ASK,
242
+ CONSTRUCT and DESCRIBE.
243
+ - `loadEngine()`: the low-level engine handle (`call(op, args)`), for the
244
+ dispatch ops the typed layer does not wrap.
245
+ - Common Logic: `clParse`, `clSerialize`, `clAlphaNorm`, `clNormalize` on the
246
+ main entry (they were on `./l4-core` only).
247
+ - `browser.js` loads the wasm with `fetch` and
248
+ `WebAssembly.instantiateStreaming`; `setAssetsUrl()` names another
249
+ directory for the engine's three files.
250
+ - `parse(text, {lenient: true})` (op `parseDocument`,
251
+ [issue 716](https://github.com/danbri/factoidal/issues/716)): the Turtle,
252
+ TriG, N-Triples and N-Quads parsers skip each bad statement, keep the good
253
+ ones and list one diagnostic per skipped statement in
254
+ `dataset.diagnostics`: `message`, `line`, `column`, `offset` (a UTF-16
255
+ index, as `ParseError.offset`) and a stable `class` (for example
256
+ `undefined-prefix`, `bad-escape`, `unexpected-token`). The new option
257
+ `maxErrors` stops the parse after that many diagnostics with one
258
+ `too-many-errors` diagnostic. `capabilities().parseDiagnostics` is `true`.
259
+ A document with no error gives the strict result and no diagnostics (a
260
+ theorem in the Lean source). RDF/XML and JSON-LD parse strictly.
261
+
262
+ Changed:
263
+
264
+ - **`ParseError.offset` is a UTF-16 code-unit index into the input string**,
265
+ so `text.slice(err.offset)` starts at the error. The F\* engine counted
266
+ UTF-8 bytes; the Lean engine counts Unicode scalar values and the wrapper
267
+ converts. (`line` is 1-based; `column` counts Unicode scalar values.) This
268
+ unit is a coordinator default, recorded in
269
+ `docs/designissues/2026-10-10-npm-lean-only.md`.
270
+ - Each SELECT solution `Map` iterates in the order of the SELECT clause
271
+ (`head.vars`); it followed the member order of the engine's JSON binding
272
+ objects, which carries no meaning.
273
+ - DESCRIBE answers the Concise Bounded Description of each named resource
274
+ (the F\* engine answered the empty graph,
275
+ [issue 702](https://github.com/danbri/factoidal/issues/702)).
276
+ - `serialize(data, {format: 'ntriples'})` answers the engine's N-Quads text
277
+ and refuses data with a named graph (N-Triples has no graph term).
278
+ - `xmlWellformed` reads a DOCTYPE with an internal subset (the F\* parser
279
+ answered `false` for any DOCTYPE); `xpathEval` is the full XPath 1.0
280
+ evaluator and its node kinds include `root` and `namespace`;
281
+ `mathmlEval` also evaluates `vector` and `matrix`; `rifEval`'s envelope
282
+ has no `rounds`/`engineMs`; `tableauMaterialise` adds `budgetHit`;
283
+ `rmlMap` reads the iteration format from the mapping's
284
+ `rml:referenceFormulation`. Record:
285
+ `docs/designissues/2026-10-10-npm-lean-only.md` section 6.
286
+ - `capabilities()` reports what the loaded wasm serves: new members
287
+ `entailment`, `hdt`, `sparql12`, `store`; `cottasBytesStore` is gone.
288
+ - `engines.node` is `>=22.12`: `index.js` hands the ES module `index.mjs`
289
+ to `require()`, so CommonJS and ES module callers share one engine and
290
+ one `Dataset` class. (Node 20 reached end of life on 2026-04-30.)
291
+
292
+ Open, each with an expected-failure test:
293
+
294
+ - A failed `SERVICE` call without `SILENT` inside `EXISTS`, and a failed
295
+ nested `SERVICE` under an outer `SILENT`
296
+ ([issue 735](https://github.com/danbri/factoidal/issues/735)). A failed
297
+ `SERVICE` call without `SILENT` elsewhere now fails the query
298
+ ([issue 717](https://github.com/danbri/factoidal/issues/717), fixed).
299
+
300
+ Deprecated: `./l4` and `./l4-core` are aliases of `.` in 0.9.x and go in
301
+ 0.10.0. (`./l4` was the low-level loader; `loadEngine()` replaces it.)
302
+
303
+ ### Earlier in 0.9.0 (before the switch; `./l4-core` was the Lean entry then)
304
+
305
+ **Lean engine (`factoidal/l4-core`): 26 more functions of the main
306
+ entry** ([issue 713](https://github.com/danbri/factoidal/issues/713),
307
+ stage 1 of making the package Lean-only). `jsonldToRdf`,
308
+ `jsonldFromRdf`, `rmlMap`, `csvwToRdf`, `xmlWellformed`, `xpathEval`,
309
+ `xsltTransform`, `schematronValidate`, `jsonSchemaValidate`,
310
+ `mathmlEval`, `xformsRecalc`, `rifEval`, `queryHdt`,
311
+ `tableauMaterialise`, `tableauDlInconsistent`, `queryRaw`, the three
312
+ extension-function and two SERVICE-endpoint registry functions, and the
313
+ five `toan*` functions now run over the Lean wasm. Signatures and
314
+ result shapes are the F\* engine's. `parse(text, {format: 'jsonld'})`
315
+ now works on this engine. `tableauMaterialise` also returns `budgetHit`
316
+ on the Lean engine. The main entry (`index.js`) is unchanged.
317
+
318
+ **`factoidal/l4-core` serves the maths, VC and DID functions, and matches the
319
+ F\* engine's envelopes** (stage 2 of
320
+ [issue 713](https://github.com/danbri/factoidal/issues/713)). New on the Lean
321
+ engine, with the signatures and result shapes `index.d.ts` declares:
322
+ `matrixDeterminant`, `matrixScalarProduct`, `matrixVectorProduct`,
323
+ `matrixOuterProduct`, `sigmoidPoints`, `sigmoidFormulaMathml`, `vcSha256Hex`,
324
+ `vcEd25519SecretToPublic`, `vcEd25519Sign`, `vcEd25519Verify`,
325
+ `vcEddsaCreateFromCanonical`, `vcEddsaVerifyFromCanonical`, `vcCheckCredential`,
326
+ `vcCheckCredentialSubject`, `vcCheckNoDataLoss`,
327
+ `vcCheckRelatedResourceDigests` and `didKeyResolve`. The Ed25519 operations run
328
+ HACL\* compiled into the wasm module; they need no `initHacl()` call. Envelope
329
+ parity ([issue 685](https://github.com/danbri/factoidal/issues/685)): a Turtle,
330
+ TriG, N-Triples or N-Quads syntax error rejects with a `ParseError` carrying
331
+ `line`, `column`, `offset` and `format` (the Lean `offset` counts Unicode scalar
332
+ values, the F\* `offset` counts UTF-8 bytes); `parse()` and `openDataset()`
333
+ record the prefixes of a Turtle or TriG document; Turtle output accepts the
334
+ `prefixes` and `literalShorthand` options and prints bare numeric and boolean
335
+ literals by default; and each document that is parsed gets its own blank-node
336
+ scope, so merging two documents that both write `_:b0` keeps two nodes. The
337
+ Lean engine still has no `{lenient: true}` parse and no SPARQL 1.2 handle
338
+ query.
339
+
340
+ **Store format: the literal index is renamed LGI3 and LGI4; re-pack older
341
+ generations.** The literal search index folds each lexical form before it takes
342
+ character 3-grams. On 2026-10-10 the fold changed from ASCII-only to the Unicode
343
+ case mapping that SPARQL `LCASE` uses
344
+ ([issue 706](https://github.com/danbri/factoidal/issues/706)), so the grams of a
345
+ non-ASCII literal differ and an index written under the old fold lacks rows the
346
+ Unicode `LCASE` keeps. The two layouts are now named LGI3 (was LGI1, sidecar
347
+ `.lgi3`) and LGI4 (was LGI2, sidecar `.lgi4`), and the manifest layout labels
348
+ changed with them. A generation packed earlier names LGI1 or LGI2; `storeOpen`,
349
+ `storeManifestInspect`, `storeQueryPlan`, `storeQuery`, `l4block-shard-activate`
350
+ and `l4block-quad-query` refuse it with the cause and ask for a re-pack.
351
+ `storeOpen` and `storeHandleList` also report `literalIndexes` and
352
+ `geoIndexes`, the number of retained blocks that hold a decoded index of each
353
+ kind. Record: `docs/designissues/2026-10-10-literal-index-lgi3.md`.
354
+
355
+ ## 0.8.0 — 2026-09-16
356
+
357
+ **Behaviour change: parsing is strict by default.** `parse()` (and
358
+ every function that parses text input) now rejects on a syntax error,
359
+ an undeclared prefix, or a relative IRI with no `baseIRI` in effect,
360
+ instead of silently dropping the affected statements. The error is a
361
+ new `class ParseError extends Error` (`name`, `line`, `column`,
362
+ `offset`, `format` — position fields present for Turtle/TriG/
363
+ N-Triples/N-Quads, absent for RDF/XML and JSON-LD, which carry a
364
+ message only), exported from every entry point (`index.js`/`.mjs`,
365
+ `wasm.js`, `l4-core.js`, `api.js`/`.mjs`, `lite.js`/`.mjs`, and
366
+ `browser.js`, which declares its own copy since it has no imports).
367
+ Pass `{lenient: true}` to `parse()` to recover instead: the returned
368
+ Dataset holds whatever the parser recovered, and the new
369
+ `dataset.diagnostics` array lists what was skipped (needs the
370
+ npm-entry engine bundle's `parseDocument` export). Issues
371
+ [344](https://github.com/danbri/factoidal/issues/344),
372
+ [680](https://github.com/danbri/factoidal/issues/680),
373
+ [681](https://github.com/danbri/factoidal/issues/681).
374
+
375
+ **Dataset handles.** `openDataset(data, {format?, baseIRI?})` parses
376
+ once and keeps the result indexed in the engine, so repeated
377
+ `query()`/`update()`/`serialize()` calls against the returned
378
+ `DatasetHandle` skip both the re-parse and the SPARQL-index rebuild a
379
+ fresh `query(ds, ...)` call pays every time (measured ~2x faster per
380
+ call on a 2,000-triple two-pattern join in this session — see
381
+ `tests/perf/npm_handle_vs_stateless.mjs`). `query(data, sparql,
382
+ options)`, `serialize(data, options)` and `canonicalize(data)` also
383
+ accept a `DatasetHandle` directly; `update(handle, ...)` rejects with
384
+ a `TypeError`, since `update()` always returns a fresh Dataset while
385
+ `handle.update()` mutates the handle in place. `select.js` (the F*/
386
+ Lean backend selector) deliberately does not route `openDataset()` —
387
+ a handle is opened against one engine's own entry object, so there is
388
+ no "same handle on the other engine" to fall through to.
389
+
390
+ **Prefixes and Turtle literal shorthand.** `Dataset` gains `.prefixes`
391
+ (the declared map from parsing, `{}` for N-Triples/N-Quads) and
392
+ `.diagnostics` (own, non-enumerable properties, so `JSON.stringify()`/
393
+ `toArray()` are unaffected either way). `serialize(data, {format:
394
+ 'turtle', prefixes?, literalShorthand?})` uses caller prefix pairs
395
+ (dropping unused caller namespaces, skipping caller labels when
396
+ auto-generating `nsN:` ones) when given, or automatically when `data`
397
+ is a Dataset with non-empty `.prefixes`; `literalShorthand` (default
398
+ `true`) controls whether `xsd:integer`/`decimal`/`double`/`boolean`
399
+ literals with a Turtle-grammar-matching lexical form print bare.
400
+ `DatasetHandle.serialize()` has the same options.
401
+
402
+ **New entry point `@factoidal/core/lite`** (`lite.js`/`.mjs`/`.d.ts`):
403
+ a smaller npm-entry ABI bundle (`factoidal-npm-entry-lite.js`, about
404
+ half the gzip size of the full bundle — see README.md's "Choosing a
405
+ bundle: full or lite") implementing the core surface (`parse`,
406
+ `query`, `update`, `serialize`, `canonicalize`, `graphs`,
407
+ `canonicalHash`, `openDataset`/`DatasetHandle`, the extension-function
408
+ and SERVICE-endpoint registration functions, `capabilities`) with no
409
+ SHACL, ShEx, OWL closure, JSON-LD, RDF/XML, CSVW, RML, RIF, XML,
410
+ XPath, VC crypto, COTTAS, or CLI bundle (no entailment regimes, no
411
+ `queryHdt`). `capabilities()` gains `profile` (`'full'` | `'lite'`),
412
+ `abiVersion`, `datasetHandles`, `parseDiagnostics`, `turtlePrefixes`.
413
+ Issue [684](https://github.com/danbri/factoidal/issues/684).
414
+
415
+ **`browser.js`: `query()` and `toRdf()` route through the npm-entry
416
+ ABI.** Whenever the persistent ABI bundle is available (already on
417
+ `globalThis`, or fetched by `loadNpmEntry()`), `query()` with `entail:
418
+ 'none'` and `output: 'json'` (both defaults), and every `toRdf()`
419
+ call, now go through it instead of the eval-per-call CLI bundle —
420
+ falling back to the CLI bundle only when loading the ABI fails. This
421
+ makes the classic-`<script>` route (README.md's "Bundlers and Content
422
+ Security Policy" §b) CSP-safe for parsing and SELECT/ASK too, not only
423
+ for the operations already ABI-routed. New `openDataset(text,
424
+ {format?, baseIRI?})` on `browser.js` returns a handle with `query`/
425
+ `update`/`serialize`/`close` over the same ABI. Issue
426
+ [682](https://github.com/danbri/factoidal/issues/682) (second half).
427
+
428
+ Three new entry points, for two storage protocols:
429
+
430
+ * `@factoidal/core/lws` — a Node `http` server for the
431
+ [Linked Web Storage Protocol 1.0 core](https://w3c.github.io/lws-protocol/lws10-core/);
432
+ * `@factoidal/core/solid/server` — the same shape for the
433
+ [Solid Protocol v0.11.0](https://solidproject.org/TR/protocol) server
434
+ conformance class, including the CORS preflight and the storage root;
435
+ * `@factoidal/core/solid/client` — the client conformance class over
436
+ `fetch`, whose every request is built by the engine and whose every
437
+ response is read by it.
438
+
439
+ Three commands: `factoidal lws-serve DIR`, `factoidal solid-serve DIR`
440
+ and `factoidal solid-client <get|put|post|delete|discover> URL`.
441
+
442
+ Every protocol decision is the Lean engine's; the hosts move bytes. The
443
+ operations are `lwsOpen`/`lwsStep`/`lwsClose`,
444
+ `solidOpen`/`solidStep`/`solidClose` and
445
+ `solidClientRequest`/`solidClientResponse` on the WebAssembly dispatch
446
+ ABI. **A module built before they landed answers `unknown op`**: the
447
+ entry points report it through their `…OpsAvailable(engine)` probe and
448
+ the commands exit 3. `DIR` is not read or written yet — the resource tree
449
+ lives in the engine handle — and Solid-OIDC token verification is not
450
+ built, so the first slice serves public resources and unauthenticated
451
+ writes. Issue
452
+ [659](https://github.com/danbri/factoidal/issues/659).
453
+
454
+ New entry point `@factoidal/core/api`: `createApi(entry, options?)`
455
+ wires the typed `parse`/`query`/`serialize`/... surface around an
456
+ already-loaded npm-entry ABI object, with no `fetch` and no `new
457
+ Function(src)` eval — the route for a bundler (esbuild, webpack,
458
+ Rollup) or a page under `Content-Security-Policy: script-src 'self'`.
459
+ `entry` accepts the `factoidalNpmEntry` object itself, a Promise of
460
+ it, or a zero-argument function returning either. `browser.js`'s
461
+ `loadNpmEntry()` now checks `globalThis.factoidalNpmEntry` before
462
+ fetching anything, so a classic `<script src="factoidal-npm-entry.js">`
463
+ tag (or the new `setNpmEntry(abi)`) makes every `browser.js` operation
464
+ already routed through that ABI CSP-safe too. `package.json`'s
465
+ `exports` map gains `./api` and direct subpaths for
466
+ `factoidal-npm-entry.js`/`.wasm.js`/`.wasm.assets/*` (already shipped
467
+ in `files`, not previously importable as package subpaths). Every
468
+ typed entry point (`factoidal`, `factoidal/wasm`, `factoidal/api`,
469
+ `factoidal/l4-core`) now reports `version` and `engine`. See
470
+ README.md's "Bundlers and Content Security Policy" section. Proved
471
+ against a real headless-Chromium page under that CSP header
472
+ (`tests/web-demos/bundler_csp_smoke.sh`) and against esbuild's bundler
473
+ (`test/bundler-esbuild.test.mjs`). Issue
474
+ [682](https://github.com/danbri/factoidal/issues/682).
475
+
476
+ README.md documents `parse()`'s output order (canonical/sorted
477
+ N-Quads, not document order) and the blank-node label scheme
478
+ (`_anonN` in document order for anonymous nodes, `p<k>_d<n>_` scope
479
+ prefixes, no RDF meaning beyond within-dataset identity), pinned by
480
+ `test/parse-order.test.js`. No behavior changed. Issue
481
+ [683](https://github.com/danbri/factoidal/issues/683).
482
+
483
+ A bare string where `parse`, `query`, `update`, `openDataset`,
484
+ `serialize`, `canonicalize` or `DatasetHandle.serialize` take an
485
+ options object now means `{ format: <string> }`, so
486
+ `serialize(ds, 'turtle')` is `serialize(ds, { format: 'turtle' })`.
487
+ Until now the string was read as an empty options object and
488
+ `serialize(ds, 'turtle')` returned N-Quads with no error (found by the
489
+ 0.8.0 release probe). Any other non-object value throws a `TypeError`
490
+ naming the function. Pinned by `test/options-format-string.test.js`.
491
+
492
+ The shipped bundles are built from a fresh extraction of the F\* OWL
493
+ closure source. The committed OCaml for `OWL.Closure` and
494
+ `OWL.DirectMapping.Filter` had lagged the `.fst` files since the
495
+ 2026-09-07 OWL soundness audit (commit 709f3c4; the "Check F\* Extraction"
496
+ workflow was red on `claude/main` from that date, runs 200 and 201),
497
+ so 0.7.1 was built from the pre-audit rules. Observable in this
498
+ release: the rule that derived `owl:sameAs` between named classes
499
+ from `owl:equivalentClass` is removed, datatype-range clashes are
500
+ decided by XSD value-space disjointness (`xsd_value_spaces_disjoint`),
501
+ and the direct-mapping filter also excludes the built-in OWL annotation
502
+ properties, not only declared ones. The npm-publish workflow re-extracts and refuses drift,
503
+ so this correction is a precondition of the release.
504
+
505
+ ## 0.7.1 — 2026-09-06
506
+
507
+ `factoidal pack --batch-bytes N` was documented in 0.7.0 and refused by the
508
+ option parser ("usage" exit 2): the value-option table for `pack` did not
509
+ list it. It is accepted now, and `tests/store-host/cli.mjs` packs with it.
510
+ No engine change; the wasm module is 0.7.0's.
511
+
3
512
  ## 0.7.0 — 2026-09-05
4
513
 
5
514
  **Wire version 10.** The command and `bin/store.mjs` read a generation
@@ -560,7 +1069,7 @@ Known limits, measured:
560
1069
  format-compatibility gate rejected stores written by the current js
561
1070
  bundle (caught by the wasm/js parity test in `test/`).
562
1071
 
563
- ## Unreleased
1072
+ ## Between 0.1.0-alpha.0 and 0.1.0 — unpublished
564
1073
 
565
1074
  - Package renamed from the placeholder `@danbri/foafos` to `factoidal`
566
1075
  (issue #403). The package was never published under the old name, so
package/NOTICE CHANGED
@@ -3,27 +3,8 @@
3
3
 
4
4
  The code in this package is Apache-2.0; see LICENSE.
5
5
 
6
- sample-store/
7
- -------------
8
-
9
- The bundled sample Shardborough store holds five IPTC NewsCodes
10
- vocabularies, converted from the publisher's RDF/XML and packed into
11
- IBK3 predicate blocks:
12
-
13
- spamfstat, videoqualifier, subjectqualifier, videocodec, spct
14
-
15
- Publisher: International Press Telecommunications Council
16
- https://iptc.org/
17
- Licence: Creative Commons Attribution 4.0 International (CC BY 4.0)
18
- https://creativecommons.org/licenses/by/4.0/
19
- Obtained through: https://github.com/danbri/skosdex third_party/skos
20
-
21
- The IRIs, labels and structure are the IPTC's. The block layout, the
22
- dictionary, the indexes and the manifest are this package's encoding of
23
- them. Redistribution of the vocabulary content stays under CC BY 4.0.
24
-
25
- hacl-wasm/
26
- ----------
6
+ HACL* (compiled into l4factoidal.wasm)
7
+ --------------------------------------
27
8
 
28
9
  HACL* verified cryptographic primitives, from
29
10
  https://github.com/hacl-star/hacl-star, Apache-2.0 / MIT. See the