eyeprolog 1.5.71 → 1.5.73
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/README.md +10 -2
- package/conformance-report.md +2 -2
- package/examples/deck/symbiotic-knowledge-graphs.md +1 -1
- package/package.json +4 -30
- package/test/README.md +33 -0
- package/test/benchmark.mjs +3 -3
- package/test/conformance/ISO-COMPLIANCE.md +9 -9
- package/test/conformance/NEUMERKEL-LATEST.md +3 -3
- package/test/conformance/NEUMERKEL-LIVE.md +6 -6
- package/test/conformance/README.md +16 -16
- package/test/conformance/WG17-SYNTAX-STATUS.md +10 -10
- package/test/conformance/wg17-syntax-cases.json +106 -2
- package/test/conformance/wg17-syntax-coverage.json +3 -3
- package/test/neumerkel.mjs +6 -6
- package/test/regression/cases-documentation-sync.mjs +17 -2
- package/test/run-neumerkel-tests.mjs +5 -9
- package/test/run-neumerkel.mjs +2 -2
- package/the-art-of-eyeprolog.md +9 -9
- package/tools/generate-library-autoload-index.mjs +1 -1
- package/tools/generate-predicate-reference.mjs +1 -1
- package/tools/report-wg17-syntax-coverage.mjs +3 -3
- package/tools/upgrade-wg17.mjs +16 -13
package/README.md
CHANGED
|
@@ -84,7 +84,7 @@ The checked [Symbiotic Knowledge Graphs example](examples/symbiotic-knowledge-gr
|
|
|
84
84
|
The same RDF → Prolog → RDF boundary is exercised by five additional checked scenarios: [cross-organization data sharing](https://eyereasoner.github.io/eyeprolog/examples/deck/cross-organization-data-sharing), [explainable EV-depot configuration](https://eyereasoner.github.io/eyeprolog/examples/deck/explainable-ev-depot-configuration), [operational incident response](https://eyereasoner.github.io/eyeprolog/examples/deck/operational-incident-response), [software supply-chain vulnerability response](https://eyereasoner.github.io/eyeprolog/examples/deck/sbom-vulnerability-response), and a [scientific evidence graph](https://eyereasoner.github.io/eyeprolog/examples/deck/scientific-evidence-graph). Together they cover policy decisions, reversible configuration reasoning, dependency-graph diagnosis, transitive SBOM exposure, and evidence aggregation with explicit disagreement.
|
|
85
85
|
|
|
86
86
|
## Benchmarks
|
|
87
|
-
EyeProlog has 19 checksum-protected wall-clock benchmarks spanning recursion/indexing, constraints, tabling/WFS, DCGs, Eyelet, search, term I/O, attributes, rewriting, and the classic Prolog naive-reverse workload. Short workloads are adaptively batched before timing so millisecond-scale noise is not mistaken for a regression. Run `npm run benchmark`; create a machine-local comparison point with `npm run benchmark
|
|
87
|
+
EyeProlog has 19 checksum-protected wall-clock benchmarks spanning recursion/indexing, constraints, tabling/WFS, DCGs, Eyelet, search, term I/O, attributes, rewriting, and the classic Prolog naive-reverse workload. Short workloads are adaptively batched before timing so millisecond-scale noise is not mistaken for a regression. Run `npm run benchmark`; create a machine-local comparison point with `npm run benchmark -- --save .benchmarks/baseline.json`; use `node test/run-benchmark-tests.mjs` for harness checks. The checked [`examples/bench.pl`](examples/bench.pl) preserves the classic Quintus 1984 `nrev/2` workload on a 30-element list. For a comparable LIPS number, run `node test/lips-benchmark.mjs`: it executes the classic failure-driven `dobench/1` and `dodummy/1` loops in Prolog, subtracts dummy-loop CPU time, and applies the historical 496 procedure calls per reversal. The generic benchmark table still shows a quick wall-clock LIPS estimate for `classic-nrev`, but `node test/lips-benchmark.mjs` is the canonical engine-speed measurement. LIPS is a historical basic-engine-speed indicator, not a whole-system performance score. Details are in [*The Art of EyeProlog*](the-art-of-eyeprolog.md).
|
|
88
88
|
For the project policy on post-ISO-standard and WG17 compatibility features such as digit separators, see [ISO/WG17 compatibility extensions](test/conformance/ISO-WG17-EXTENSIONS.md).
|
|
89
89
|
## Development
|
|
90
90
|
```sh
|
|
@@ -93,5 +93,13 @@ cd eyeprolog
|
|
|
93
93
|
npm install
|
|
94
94
|
npm test
|
|
95
95
|
```
|
|
96
|
-
|
|
96
|
+
The npm command list is deliberately small:
|
|
97
|
+
|
|
98
|
+
- `npm test` (or `npm run test`): run the release gate, including live upstream conformity checks.
|
|
99
|
+
- `npm run conformance:update:wg17`: update the vendored WG17 syntax cases and their inventory documentation.
|
|
100
|
+
- `npm run generate`: rebuild generated library and book files.
|
|
101
|
+
- `npm run benchmark`: run the wall-clock benchmarks.
|
|
102
|
+
|
|
103
|
+
Use `npm test -- --offline` for a network-free local pass. Focused checks remain available directly, for example `node test/run-regression.mjs docs` or `node test/run-wg17.mjs`; see [test runners](test/README.md). The automatic version hooks still run the release gate, refresh and stage conformance reports, and push the release. Detailed upstream report maintenance is documented in the [conformance guide](test/conformance/README.md).
|
|
104
|
+
|
|
97
105
|
EyeProlog is released under the [MIT License](LICENSE.md).
|
package/conformance-report.md
CHANGED
|
@@ -15,9 +15,9 @@ cached source bytes, avoiding a second live fetch and its race window.
|
|
|
15
15
|
|
|
16
16
|
| Gate | Passed | Total | Status |
|
|
17
17
|
|---|---:|---:|---|
|
|
18
|
-
| WG17 syntax |
|
|
18
|
+
| WG17 syntax | 379 | 379 | pass |
|
|
19
19
|
|
|
20
|
-
The WG17 syntax row executes the vendored
|
|
20
|
+
The WG17 syntax row executes the vendored 379-case conformity-testing matrix
|
|
21
21
|
against EyeProlog's strict ISO reader/writer. A behavior fix such as operator-token
|
|
22
22
|
spelling therefore changes this report even when no corpus file is added or removed.
|
|
23
23
|
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "1.5.
|
|
6
|
+
"version": "1.5.73",
|
|
7
7
|
"description": "EyeProlog turns facts and rules into answers and proofs.",
|
|
8
8
|
"type": "module",
|
|
9
9
|
"main": "./index.js",
|
|
@@ -46,36 +46,10 @@
|
|
|
46
46
|
},
|
|
47
47
|
"scripts": {
|
|
48
48
|
"test": "node test/run-all.mjs",
|
|
49
|
-
"
|
|
50
|
-
"test:conformance": "node test/run-conformance-all.mjs",
|
|
51
|
-
"test:conformance:offline": "node test/run-conformance-all.mjs --offline",
|
|
52
|
-
"test:neumerkel": "node test/run-neumerkel.mjs",
|
|
53
|
-
"test:neumerkel:cached": "node test/run-neumerkel.mjs --cached",
|
|
54
|
-
"test:neumerkel:harness": "node test/run-neumerkel-tests.mjs",
|
|
55
|
-
"test:iso": "node test/run-iso-strict.mjs",
|
|
56
|
-
"test:wg17": "node test/run-wg17.mjs",
|
|
57
|
-
"test:regression": "node test/run-regression.mjs",
|
|
58
|
-
"test:examples": "node test/run-examples.mjs",
|
|
59
|
-
"test:interop": "node test/run-interop.mjs",
|
|
60
|
-
"test:playground": "node test/run-playground.mjs",
|
|
61
|
-
"test:architecture": "node test/run-architecture.mjs",
|
|
62
|
-
"test:openrulebench": "node test/run-openrulebench.mjs",
|
|
63
|
-
"test:benchmark": "node test/run-benchmark-tests.mjs",
|
|
49
|
+
"conformance:update:wg17": "node tools/upgrade-wg17.mjs",
|
|
64
50
|
"benchmark": "node test/benchmark.mjs",
|
|
65
|
-
"benchmark:lips": "node test/lips-benchmark.mjs",
|
|
66
|
-
"benchmark:baseline": "node test/benchmark.mjs --save .benchmarks/baseline.json",
|
|
67
|
-
"conformance:update": "npm run conformance:update:wg17 && npm run conformance:update:neumerkel",
|
|
68
|
-
"conformance:report": "node test/run-conformance-report.mjs conformance-report.md",
|
|
69
51
|
"generate": "node tools/generate-library-autoload-index.mjs && node tools/generate-predicate-reference.mjs && node tools/extract-book-examples.mjs",
|
|
70
|
-
"
|
|
71
|
-
"
|
|
72
|
-
"preversion": "npm test && npm run conformance:sync:neumerkel && npm run conformance:report && git add test/conformance/NEUMERKEL-LATEST.md conformance-report.md",
|
|
73
|
-
"postversion": "git push origin HEAD --follow-tags",
|
|
74
|
-
"conformance:update:wg17": "node tools/upgrade-wg17.mjs",
|
|
75
|
-
"conformance:update:neumerkel": "node test/run-neumerkel.mjs --update-report",
|
|
76
|
-
"conformance:check:neumerkel": "node test/run-neumerkel.mjs --cached --verify-report",
|
|
77
|
-
"conformance:sync:neumerkel": "node test/run-neumerkel.mjs --cached --update-report",
|
|
78
|
-
"test:http-json": "node test/run-http-json.mjs",
|
|
79
|
-
"test:iso-part2-amendment": "node test/run-iso-part2-amendment.mjs"
|
|
52
|
+
"preversion": "npm test && node test/run-neumerkel.mjs --cached --update-report && node test/run-conformance-report.mjs conformance-report.md && git add test/conformance/NEUMERKEL-LATEST.md conformance-report.md",
|
|
53
|
+
"postversion": "git push origin HEAD --follow-tags"
|
|
80
54
|
}
|
|
81
55
|
}
|
package/test/README.md
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Test runners
|
|
2
|
+
|
|
3
|
+
Normally, run `npm test`. Use `npm test -- --offline` to skip live upstream fetching.
|
|
4
|
+
`npm run conformance:update:wg17` refreshes the vendored WG17 snapshot.
|
|
5
|
+
|
|
6
|
+
For development, run a focused check directly from the repository root:
|
|
7
|
+
|
|
8
|
+
```sh
|
|
9
|
+
node test/run-regression.mjs # all regression sections
|
|
10
|
+
node test/run-regression.mjs docs # documentation checks only
|
|
11
|
+
node test/run-conformance-all.mjs # conformance layers; accepts --offline
|
|
12
|
+
node test/run-wg17.mjs # vendored WG17 syntax
|
|
13
|
+
node test/run-iso-strict.mjs # strict ISO core
|
|
14
|
+
node test/run-iso-part2-amendment.mjs
|
|
15
|
+
node test/run-neumerkel.mjs # live upstream; --cached reproduces last fetch
|
|
16
|
+
node test/run-neumerkel-tests.mjs # upstream-fetch harness
|
|
17
|
+
node test/run-examples.mjs
|
|
18
|
+
node test/run-playground.mjs
|
|
19
|
+
node test/run-architecture.mjs
|
|
20
|
+
node test/run-openrulebench.mjs
|
|
21
|
+
node test/run-http-json.mjs
|
|
22
|
+
node test/run-interop.mjs # requires the comparison engines
|
|
23
|
+
node test/run-benchmark-tests.mjs # benchmark harness
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
These runners retain their existing options; there is no separate npm alias for
|
|
27
|
+
each one. Focused checks do not replace the full release gate.
|
|
28
|
+
|
|
29
|
+
For performance measurements, use `npm run benchmark`. Save a local baseline with
|
|
30
|
+
`npm run benchmark -- --save .benchmarks/baseline.json`, or run
|
|
31
|
+
`node test/lips-benchmark.mjs` for the classic LIPS measurement.
|
|
32
|
+
|
|
33
|
+
See the [conformance guide](conformance/README.md) for report maintenance.
|
package/test/benchmark.mjs
CHANGED
|
@@ -102,7 +102,7 @@ if (baselinePath != null) {
|
|
|
102
102
|
const loaded = JSON.parse(await fs.readFile(baselinePath, 'utf8'));
|
|
103
103
|
if (loaded.format === 2) baseline = loaded;
|
|
104
104
|
else {
|
|
105
|
-
baselineWarning = `Ignoring legacy timing baseline format ${loaded.format ?? 'unknown'}; regenerate it with npm run benchmark
|
|
105
|
+
baselineWarning = `Ignoring legacy timing baseline format ${loaded.format ?? 'unknown'}; regenerate it with npm run benchmark -- --save .benchmarks/baseline.json.`;
|
|
106
106
|
baselinePath = null;
|
|
107
107
|
}
|
|
108
108
|
}
|
|
@@ -296,10 +296,10 @@ if (options.json) {
|
|
|
296
296
|
|
|
297
297
|
process.stdout.write(`\n${results.length} benchmarks; ${options.runs} measured batch${options.runs === 1 ? '' : 'es'} each after ${options.warmup} warm-up batch${options.warmup === 1 ? '' : 'es'}, calibrated after one priming execution toward ${options.targetMs} ms per batch.\n`);
|
|
298
298
|
if (baselineWarning) process.stdout.write(`${baselineWarning}\n`);
|
|
299
|
-
if (baselinePath == null && !baselineWarning) process.stdout.write('No timing baseline found; run npm run benchmark
|
|
299
|
+
if (baselinePath == null && !baselineWarning) process.stdout.write('No timing baseline found; run npm run benchmark -- --save .benchmarks/baseline.json to create .benchmarks/baseline.json.\n');
|
|
300
300
|
if (options.save != null) process.stdout.write(`Saved timing baseline: ${path.relative(root, options.save)}\n`);
|
|
301
301
|
process.stdout.write('Change compares the current median/op directly with the saved baseline median/op; the measured range is shown separately.\n');
|
|
302
|
-
process.stdout.write('The classic-nrev LIPS column is a quick wall-clock estimate. Use
|
|
302
|
+
process.stdout.write('The classic-nrev LIPS column is a quick wall-clock estimate. Use node test/lips-benchmark.mjs for the Quintus-style dummy-subtracted CPU measurement.\n');
|
|
303
303
|
if (summary.comparable > 0) {
|
|
304
304
|
process.stdout.write('Suite score is the geometric mean of current/baseline ratios, so every benchmark has equal relative weight; Time-weighted total compares summed medians and is dominated by longer workloads.\n');
|
|
305
305
|
}
|
|
@@ -23,7 +23,7 @@ relevant implementation-dependent overlap choice to an explicit review outcome.
|
|
|
23
23
|
|
|
24
24
|
| Requirement | Status | EyeProlog evidence / remaining work |
|
|
25
25
|
| --- | --- | --- |
|
|
26
|
-
| 5.1(a) prepare conforming Prolog text | covered | Clause 6 token/term production and rejection families are mapped by the strict production gate and the complete
|
|
26
|
+
| 5.1(a) prepare conforming Prolog text | covered | Clause 6 token/term production and rejection families are mapped by the strict production gate and the complete 379-case vendored WG17 syntax matrix; 7.4 preparation/directive behavior is separately closed. |
|
|
27
27
|
| 5.1(b) execute conforming Prolog goals | covered | Clause 7 term/control/execution semantics, the higher-level 7.10 stream model, 7.11 flags, the 7.12 error envelope, all 8.2-8.17 built-in rows, and Clause 9 arithmetic have explicit executable dispositions. |
|
|
28
28
|
| 5.1(c) reject nonconforming text/read-terms | covered | WG17 negative syntax cases, focused malformed-production/escape/comment/operator cases, read-term syntax errors, and strict rejection of implementation-specific syntax provide explicit rejection evidence across the Clause 6 families. |
|
|
29
29
|
| 5.1(d) document permitted variations | covered | The clause-by-clause [ISO 5.4 decision index](ISO-IMPLEMENTATION-DEFINED.md) records every explicit implementation-defined decision found in the Part 1 + Corrigenda baseline and separately inventories implementation-specific extension families. The index retains an `gap` category for future discoveries; no current release-facing row depends on one. |
|
|
@@ -35,7 +35,7 @@ relevant implementation-dependent overlap choice to an explicit review outcome.
|
|
|
35
35
|
|
|
36
36
|
| Standard area | Status | Current evidence |
|
|
37
37
|
| --- | --- | --- |
|
|
38
|
-
| Clause 6 — tokens, terms, lists, operators, quoted text | covered | The strict Clause 6 gate maps atomic/variable/compound/operator/list/curly/double-quoted term forms, layout/comments, quoted escapes, integer bases/character codes, floating tokens, and solo/meta token boundaries, with malformed counterparts rejected. The complete
|
|
38
|
+
| Clause 6 — tokens, terms, lists, operators, quoted text | covered | The strict Clause 6 gate maps atomic/variable/compound/operator/list/curly/double-quoted term forms, layout/comments, quoted escapes, integer bases/character codes, floating tokens, and solo/meta token boundaries, with malformed counterparts rejected. The complete 379-case WG17 syntax matrix provides externally sourced production-level expectations, and a cross-profile gate verifies that normal syntax extensions preserve every strict-accepted standard observation. The implementation-defined 6.5/6.6 PCS/collation choices are documented separately. |
|
|
39
39
|
| 7.1-7.3 — term types, term order, unification | covered | [ISO-TERM-SEMANTICS-MATRIX.md](ISO-TERM-SEMANTICS-MATRIX.md) records the five mutually exclusive strict term types, derived variable/compound/list notions, the complete standard-order classes and implementation-dependent variable-order choice, NSTO MGU/failure behavior, and EyeProlog's permitted consistent occurs-check failure for Part 1's undefined STO ordinary-unification cases. The normal JavaScript API string term is documented as a 5.5.4 extension and rejected at strict program/goal entry. |
|
|
40
40
|
| 7.4 — Prolog text and directives | covered | [ISO-PROLOG-TEXT-EXECUTION-MATRIX.md](ISO-PROLOG-TEXT-EXECUTION-MATRIX.md) closes the preparation/directive rows: declaration semantics, source clauses, cross-text operators/character conversion/flags, initialization order/lifetime, `include/1`, and one-time `ensure_loaded/1`, with implementation-defined cross-text choices indexed under 5.4. |
|
|
41
41
|
| 7.5-7.6 — database and term/clause conversion | covered | [ISO-PROLOG-TEXT-EXECUTION-MATRIX.md](ISO-PROLOG-TEXT-EXECUTION-MATRIX.md) closes static/dynamic and private/public procedure semantics, clause order, logical-update visibility, empty/unknown lifetime, and term/body/clause conversion. Source and runtime assertion conversion recurse through `,/2`, `;/2`, and `->/2`, preserve variable identity, and protect standardized static/control procedures. |
|
|
@@ -286,14 +286,14 @@ architecture gates. The upstream case counts are discovered dynamically.
|
|
|
286
286
|
Useful focused commands are:
|
|
287
287
|
|
|
288
288
|
```sh
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
npm
|
|
289
|
+
node test/run-conformance-all.mjs
|
|
290
|
+
node test/run-neumerkel.mjs
|
|
291
|
+
node test/run-iso-strict.mjs
|
|
292
|
+
node test/run-wg17.mjs
|
|
293
|
+
npm test -- --offline
|
|
294
294
|
```
|
|
295
295
|
|
|
296
|
-
`test
|
|
296
|
+
`npm test -- --offline` is a development/reproduction aid; it is not sufficient for a
|
|
297
297
|
release claim that says EyeProlog passes the latest Neumerkel suites. Expected
|
|
298
298
|
conformance outputs are never auto-accepted.
|
|
299
299
|
|
|
@@ -307,7 +307,7 @@ post-N289 STC drafts remain review input until standardized.
|
|
|
307
307
|
| Criterion | Status | Evidence |
|
|
308
308
|
| --- | --- | --- |
|
|
309
309
|
| Clause 5 processor obligations have explicit dispositions | covered | `ISO-PROCESSOR-REQUIREMENTS.md` gives explicit outcomes for 5.1-5.5, including the strict/normal extension boundary. |
|
|
310
|
-
| Clause 6 lexical/syntactic requirements have explicit dispositions | covered | the strict Clause 6 production/rejection gate and the
|
|
310
|
+
| Clause 6 lexical/syntactic requirements have explicit dispositions | covered | the strict Clause 6 production/rejection gate and the 379-case vendored WG17 matrix cover the standard families; cross-profile preservation verifies that normal extensions do not reinterpret strict-accepted text. |
|
|
311
311
|
| Clause 7 semantic requirements have explicit dispositions | covered | 7.1-7.12 now have explicit semantic, implementation-defined, or error-envelope dispositions backed by strict tests and the specialized matrices. |
|
|
312
312
|
| Clause 8 built-in modes/errors have explicit dispositions | covered | `ISO-BUILTIN-MODE-ERROR-MATRIX.md` accounts for 8.2-8.17 condition by condition, using grouped rows only where every grouped condition and its evidence are named |
|
|
313
313
|
| Clause 9 evaluable-functor requirements have explicit dispositions | covered | `ISO-EVALUABLE-FUNCTOR-MATRIX.md` plus the strict arithmetic regression closes the published Part 1 + Corrigenda arithmetic rows |
|
|
@@ -31,8 +31,8 @@ Counts are output from upstream, not hard-coded test constants.
|
|
|
31
31
|
Exact fetched bytes, SHA-256 hashes, fetch timestamps, and HTTP validators remain under
|
|
32
32
|
Git-ignored `.cache/neumerkel/` for local inspection/reproduction and are intentionally not committed.
|
|
33
33
|
A normal test run warns when this tracked report is stale. Refresh directly from live
|
|
34
|
-
upstream with `
|
|
35
|
-
snapshot already fetched by `npm test` with `
|
|
36
|
-
`
|
|
34
|
+
upstream with `node test/run-neumerkel.mjs --update-report`, or sync the exact successful
|
|
35
|
+
snapshot already fetched by `npm test` with `node test/run-neumerkel.mjs --cached --update-report`.
|
|
36
|
+
`node test/run-neumerkel.mjs --cached --verify-report` verifies the tracked report against that last
|
|
37
37
|
successful live snapshot without fetching upstream a second time.
|
|
38
38
|
|
|
@@ -4,7 +4,7 @@ EyeProlog treats Ulrich Neumerkel's current ISO/WG17 conformity material as a
|
|
|
4
4
|
moving upstream release gate, not as a frozen snapshot with permanent case
|
|
5
5
|
counts.
|
|
6
6
|
|
|
7
|
-
`
|
|
7
|
+
`node test/run-neumerkel.mjs` fetches these seven TU Wien sources on every live run:
|
|
8
8
|
|
|
9
9
|
1. `conformity_testing` — Part 1 syntax/reader/writer matrix;
|
|
10
10
|
2. `number_chars_cont_quad.pl` — `number_chars/2` continuation corpus;
|
|
@@ -32,13 +32,13 @@ Markdown no longer matches, the test still reflects engine conformance and print
|
|
|
32
32
|
warning with the refresh command:
|
|
33
33
|
|
|
34
34
|
```sh
|
|
35
|
-
|
|
35
|
+
node test/run-neumerkel.mjs --update-report
|
|
36
36
|
```
|
|
37
37
|
|
|
38
38
|
Commit the resulting `test/conformance/NEUMERKEL-LATEST.md` after reviewing the
|
|
39
|
-
change. After a successful `npm test`, `
|
|
39
|
+
change. After a successful `npm test`, `node test/run-neumerkel.mjs --cached --update-report` writes
|
|
40
40
|
the tracked report from the exact cached source bytes that just passed, avoiding a
|
|
41
|
-
second network fetch. `
|
|
41
|
+
second network fetch. `node test/run-neumerkel.mjs --cached --verify-report` verifies the tracked
|
|
42
42
|
report against that same last successful snapshot. The npm version lifecycle
|
|
43
43
|
uses this race-free sync path and stages the generated reports into the release
|
|
44
44
|
commit. The tracked report intentionally omits fetch timestamps and HTTP validators,
|
|
@@ -53,14 +53,14 @@ Git-ignored: it is an inspection/reproduction cache, not published project evide
|
|
|
53
53
|
Use:
|
|
54
54
|
|
|
55
55
|
```sh
|
|
56
|
-
|
|
56
|
+
node test/run-neumerkel.mjs
|
|
57
57
|
```
|
|
58
58
|
|
|
59
59
|
for the canonical live check. For offline reproduction of the exact last live
|
|
60
60
|
fetch, use:
|
|
61
61
|
|
|
62
62
|
```sh
|
|
63
|
-
|
|
63
|
+
node test/run-neumerkel.mjs --cached
|
|
64
64
|
```
|
|
65
65
|
|
|
66
66
|
The cached command never claims to check the latest upstream suites by itself.
|
|
@@ -83,39 +83,39 @@ npm test
|
|
|
83
83
|
For an offline-only development pass:
|
|
84
84
|
|
|
85
85
|
```sh
|
|
86
|
-
npm
|
|
86
|
+
npm test -- --offline
|
|
87
87
|
```
|
|
88
88
|
|
|
89
89
|
The conformance commands are:
|
|
90
90
|
|
|
91
91
|
```sh
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
92
|
+
node test/run-conformance-all.mjs # live Neumerkel + local ISO/conformance layers
|
|
93
|
+
node test/run-conformance-all.mjs --offline # same local layers, no network
|
|
94
|
+
node test/run-neumerkel.mjs # the seven live upstream suites only
|
|
95
|
+
node test/run-neumerkel.mjs --cached # exact last fetched bytes; reproduction only
|
|
96
|
+
node test/run-neumerkel.mjs --cached --verify-report # verify tracked report against last successful live snapshot
|
|
97
|
+
node test/run-iso-strict.mjs # Part 1 + Corrigenda strict-core processor gate
|
|
98
|
+
node test/run-iso-part2-amendment.mjs # 2013 Part 2 amendment module requirements
|
|
99
|
+
node test/run-wg17.mjs # vendored reviewed WG17 syntax regression
|
|
100
100
|
```
|
|
101
101
|
|
|
102
|
-
`test
|
|
103
|
-
fetch because a cache exists. The runner discovers the number of active tests from those sources and fails on any newly introduced case EyeProlog does not pass. If the stable, tracked [NEUMERKEL-LATEST.md](NEUMERKEL-LATEST.md) is stale, normal tests warn rather than turning a passing engine run into a failure. `
|
|
102
|
+
`node test/run-neumerkel.mjs` always fetches the current TU Wien sources. It does not skip a
|
|
103
|
+
fetch because a cache exists. The runner discovers the number of active tests from those sources and fails on any newly introduced case EyeProlog does not pass. If the stable, tracked [NEUMERKEL-LATEST.md](NEUMERKEL-LATEST.md) is stale, normal tests warn rather than turning a passing engine run into a failure. `node test/run-neumerkel.mjs --update-report` performs a fresh live run and refreshes the report; after `npm test`, `node test/run-neumerkel.mjs --cached --update-report` refreshes it from the exact successful cached snapshot; and `node test/run-neumerkel.mjs --cached --verify-report` verifies that snapshot without a second network fetch. Exact bytes, SHA-256 hashes, timestamps, and HTTP validators stay under Git-ignored `.cache/neumerkel/` for inspection/reproduction only. See [NEUMERKEL-LIVE.md](NEUMERKEL-LIVE.md).
|
|
104
104
|
|
|
105
|
-
The vendored WG17 syntax snapshot is intentionally secondary. Update
|
|
105
|
+
The vendored WG17 syntax snapshot is intentionally secondary. Update it with `npm run conformance:update:wg17`. For focused upstream report maintenance and verification:
|
|
106
106
|
|
|
107
107
|
```sh
|
|
108
108
|
npm run conformance:update:wg17
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
109
|
+
node test/run-neumerkel.mjs --update-report
|
|
110
|
+
node test/run-neumerkel.mjs --cached --update-report
|
|
111
|
+
node test/run-wg17.mjs
|
|
112
112
|
```
|
|
113
113
|
|
|
114
114
|
Every vendored syntax case is still checked against its upstream Codex
|
|
115
115
|
expectation; reviewed exact outcomes are an additional regression lock rather
|
|
116
116
|
than an alternative acceptance rule.
|
|
117
117
|
|
|
118
|
-
Regenerate the top-level local-corpus report with `
|
|
118
|
+
Regenerate the top-level local-corpus report with `node test/run-conformance-report.mjs conformance-report.md`. It links to [NEUMERKEL-LATEST.md](NEUMERKEL-LATEST.md) rather than duplicating live evidence. Counts in the tracked Neumerkel report are generated evidence, not permanent constants in project policy.
|
|
119
119
|
|
|
120
120
|
Run a matching local file-based conformance subset directly with:
|
|
121
121
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# WG17 syntax traceability status
|
|
2
2
|
|
|
3
3
|
Source: [Conformity Testing I: Syntax](https://www.complang.tuwien.ac.at/ulrich/iso-prolog/conformity_testing)
|
|
4
|
-
Upstream inventory checked: 2026-09-
|
|
4
|
+
Upstream inventory checked: 2026-09-10
|
|
5
5
|
|
|
6
6
|
This ledger counts an upstream case when its WG17 identifier, query, and
|
|
7
7
|
expected ISO disposition are stored in the offline executable matrix. Every
|
|
@@ -20,25 +20,25 @@ A represented case still has to pass the executable upstream assertion in
|
|
|
20
20
|
|
|
21
21
|
| Measure | Count |
|
|
22
22
|
| --- | ---: |
|
|
23
|
-
| Active upstream cases |
|
|
24
|
-
| Upstream cases represented in the executable matrix |
|
|
23
|
+
| Active upstream cases | 379 |
|
|
24
|
+
| Upstream cases represented in the executable matrix | 379 (100.0%) |
|
|
25
25
|
| Not yet traced one-by-one | 0 |
|
|
26
26
|
| Deleted upstream identifiers | #20, #273 |
|
|
27
27
|
|
|
28
28
|
The matrix runs in strict ISO stream-reader mode as part of `npm test`. The
|
|
29
29
|
3 upstream `waits` cases are checked through EyeProlog's interactive input
|
|
30
|
-
hook. All
|
|
30
|
+
hook. All 379 executable cases are independently checked against the
|
|
31
31
|
upstream Codex expectation. 365 cases additionally retain exact reviewed
|
|
32
|
-
outcomes for stronger regression checking;
|
|
32
|
+
outcomes for stronger regression checking; 14 cases currently rely on the upstream assertion alone.
|
|
33
33
|
|
|
34
34
|
## Traceable evidence
|
|
35
35
|
|
|
36
36
|
| Executable evidence | Referenced IDs | WG17 cases |
|
|
37
37
|
| --- | ---: | --- |
|
|
38
|
-
| [complete offline executable matrix](../run-wg17.mjs) |
|
|
38
|
+
| [complete offline executable matrix](../run-wg17.mjs) | 379 | #1–#19, #21–#272, #274–#381 |
|
|
39
39
|
|
|
40
|
-
The evidence groups overlap. Their union is **
|
|
41
|
-
#1–#19, #21–#272, #274–#
|
|
40
|
+
The evidence groups overlap. Their union is **379** active cases:
|
|
41
|
+
#1–#19, #21–#272, #274–#381.
|
|
42
42
|
|
|
43
43
|
## Untraced upstream identifiers
|
|
44
44
|
|
|
@@ -46,6 +46,6 @@ None.
|
|
|
46
46
|
|
|
47
47
|
## Maintenance
|
|
48
48
|
|
|
49
|
-
1. Run `npm run conformance:update` to reconcile the dated fixture with upstream.
|
|
49
|
+
1. Run `npm run conformance:update:wg17` to reconcile the dated fixture with upstream.
|
|
50
50
|
2. Review every new or changed ISO expectation before adding its expected outcome.
|
|
51
|
-
3. Run `
|
|
51
|
+
3. Run `node test/run-wg17.mjs` and keep this generated status page synchronized.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"source": "https://www.complang.tuwien.ac.at/ulrich/iso-prolog/conformity_testing",
|
|
3
|
-
"checkedOn": "2026-09-
|
|
3
|
+
"checkedOn": "2026-09-10",
|
|
4
4
|
"protocol": "Each query is read and executed in strict ISO mode; /**/ rows reuse the preceding setup.",
|
|
5
5
|
"cases": [
|
|
6
6
|
{
|
|
@@ -5557,8 +5557,112 @@
|
|
|
5557
5557
|
}
|
|
5558
5558
|
]
|
|
5559
5559
|
}
|
|
5560
|
+
},
|
|
5561
|
+
{
|
|
5562
|
+
"id": 369,
|
|
5563
|
+
"query": "writeq(?-).",
|
|
5564
|
+
"input": "writeq(?-).",
|
|
5565
|
+
"readCount": 1,
|
|
5566
|
+
"expected": "?-",
|
|
5567
|
+
"assertion": "upstream"
|
|
5568
|
+
},
|
|
5569
|
+
{
|
|
5570
|
+
"id": 370,
|
|
5571
|
+
"query": "writeq(./*).",
|
|
5572
|
+
"input": "writeq(./*).",
|
|
5573
|
+
"readCount": 1,
|
|
5574
|
+
"expected": "./*",
|
|
5575
|
+
"assertion": "upstream"
|
|
5576
|
+
},
|
|
5577
|
+
{
|
|
5578
|
+
"id": 371,
|
|
5579
|
+
"query": "writeq({*}).",
|
|
5580
|
+
"input": "writeq({*}).",
|
|
5581
|
+
"readCount": 1,
|
|
5582
|
+
"expected": "{*}",
|
|
5583
|
+
"assertion": "upstream"
|
|
5584
|
+
},
|
|
5585
|
+
{
|
|
5586
|
+
"id": 372,
|
|
5587
|
+
"query": "writeq(.*).",
|
|
5588
|
+
"input": "writeq(.*).",
|
|
5589
|
+
"readCount": 1,
|
|
5590
|
+
"expected": ".*",
|
|
5591
|
+
"assertion": "upstream"
|
|
5592
|
+
},
|
|
5593
|
+
{
|
|
5594
|
+
"id": 373,
|
|
5595
|
+
"query": "writeq(...*).",
|
|
5596
|
+
"input": "writeq(...*).",
|
|
5597
|
+
"readCount": 1,
|
|
5598
|
+
"expected": "...*",
|
|
5599
|
+
"assertion": "upstream"
|
|
5600
|
+
},
|
|
5601
|
+
{
|
|
5602
|
+
"id": 374,
|
|
5603
|
+
"query": "[.",
|
|
5604
|
+
"input": "[.",
|
|
5605
|
+
"readCount": 1,
|
|
5606
|
+
"expected": "syntax err.",
|
|
5607
|
+
"assertion": "upstream"
|
|
5608
|
+
},
|
|
5609
|
+
{
|
|
5610
|
+
"id": 375,
|
|
5611
|
+
"query": "{.",
|
|
5612
|
+
"input": "{.",
|
|
5613
|
+
"readCount": 1,
|
|
5614
|
+
"expected": "syntax err.",
|
|
5615
|
+
"assertion": "upstream"
|
|
5616
|
+
},
|
|
5617
|
+
{
|
|
5618
|
+
"id": 376,
|
|
5619
|
+
"query": "writeq(E).",
|
|
5620
|
+
"input": "writeq(E).",
|
|
5621
|
+
"readCount": 1,
|
|
5622
|
+
"expected": "e.g. _1",
|
|
5623
|
+
"assertion": "upstream"
|
|
5624
|
+
},
|
|
5625
|
+
{
|
|
5626
|
+
"id": 377,
|
|
5627
|
+
"query": "write_term(., [ignore_ops(true)]).",
|
|
5628
|
+
"input": "write_term(., [ignore_ops(true)]).",
|
|
5629
|
+
"readCount": 1,
|
|
5630
|
+
"expected": ".",
|
|
5631
|
+
"assertion": "upstream"
|
|
5632
|
+
},
|
|
5633
|
+
{
|
|
5634
|
+
"id": 380,
|
|
5635
|
+
"query": "write_term([' '], [ignore_ops(true)]).",
|
|
5636
|
+
"input": "write_term([' '], [ignore_ops(true)]).",
|
|
5637
|
+
"readCount": 1,
|
|
5638
|
+
"expected": ".( ,[])",
|
|
5639
|
+
"assertion": "upstream"
|
|
5640
|
+
},
|
|
5641
|
+
{
|
|
5642
|
+
"id": 378,
|
|
5643
|
+
"query": "writeq(--> /2).",
|
|
5644
|
+
"input": "writeq(--> /2).",
|
|
5645
|
+
"readCount": 1,
|
|
5646
|
+
"expected": "syntax err.",
|
|
5647
|
+
"assertion": "upstream"
|
|
5648
|
+
},
|
|
5649
|
+
{
|
|
5650
|
+
"id": 379,
|
|
5651
|
+
"query": "writeq((-->)/2).",
|
|
5652
|
+
"input": "writeq((-->)/2).",
|
|
5653
|
+
"readCount": 1,
|
|
5654
|
+
"expected": "(-->)/2",
|
|
5655
|
+
"assertion": "upstream"
|
|
5656
|
+
},
|
|
5657
|
+
{
|
|
5658
|
+
"id": 381,
|
|
5659
|
+
"query": "Finis ().",
|
|
5660
|
+
"input": "Finis ().",
|
|
5661
|
+
"readCount": 1,
|
|
5662
|
+
"expected": "syntax err.",
|
|
5663
|
+
"assertion": "upstream"
|
|
5560
5664
|
}
|
|
5561
5665
|
],
|
|
5562
5666
|
"sourceRevision": "1.300",
|
|
5563
|
-
"sourceSha256": "
|
|
5667
|
+
"sourceSha256": "db1edfc48e065b90169be55cd93a2a62b32f9dacb2fd0707667590c1a7536e69"
|
|
5564
5668
|
}
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"source": "https://www.complang.tuwien.ac.at/ulrich/iso-prolog/conformity_testing",
|
|
3
|
-
"checkedOn": "2026-09-
|
|
3
|
+
"checkedOn": "2026-09-10",
|
|
4
4
|
"upstream": {
|
|
5
5
|
"firstId": 1,
|
|
6
|
-
"lastId":
|
|
6
|
+
"lastId": 381,
|
|
7
7
|
"deletedIds": [
|
|
8
8
|
20,
|
|
9
9
|
273
|
|
10
10
|
],
|
|
11
|
-
"activeCases":
|
|
11
|
+
"activeCases": 379
|
|
12
12
|
},
|
|
13
13
|
"evidence": [
|
|
14
14
|
{
|
package/test/neumerkel.mjs
CHANGED
|
@@ -59,8 +59,8 @@ async function fetchOne(source) {
|
|
|
59
59
|
} catch (error) {
|
|
60
60
|
throw new Error(
|
|
61
61
|
`Neumerkel live fetch failed for ${source.key} (${source.url}). ` +
|
|
62
|
-
'The canonical conformance gate requires network access; use npm
|
|
63
|
-
'for a network-free local run or
|
|
62
|
+
'The canonical conformance gate requires network access; use npm test -- --offline ' +
|
|
63
|
+
'for a network-free local run or node test/run-neumerkel.mjs --cached to reproduce the last live fetch.',
|
|
64
64
|
{ cause: error },
|
|
65
65
|
);
|
|
66
66
|
}
|
|
@@ -88,7 +88,7 @@ async function fetchOne(source) {
|
|
|
88
88
|
function readCachedOne(source, cacheDir) {
|
|
89
89
|
const filename = path.join(cacheDir, source.filename);
|
|
90
90
|
if (!fs.existsSync(filename)) {
|
|
91
|
-
throw new Error(`Neumerkel cache is incomplete: missing ${path.relative(packageRoot, filename)}; run
|
|
91
|
+
throw new Error(`Neumerkel cache is incomplete: missing ${path.relative(packageRoot, filename)}; run node test/run-neumerkel.mjs online first`);
|
|
92
92
|
}
|
|
93
93
|
const bytes = new Uint8Array(fs.readFileSync(filename));
|
|
94
94
|
return {
|
|
@@ -476,9 +476,9 @@ export function formatNeumerkelMarkdown({ summary }) {
|
|
|
476
476
|
'Exact fetched bytes, SHA-256 hashes, fetch timestamps, and HTTP validators remain under',
|
|
477
477
|
'Git-ignored `.cache/neumerkel/` for local inspection/reproduction and are intentionally not committed.',
|
|
478
478
|
'A normal test run warns when this tracked report is stale. Refresh directly from live',
|
|
479
|
-
'upstream with `
|
|
480
|
-
'snapshot already fetched by `npm test` with `
|
|
481
|
-
'`
|
|
479
|
+
'upstream with `node test/run-neumerkel.mjs --update-report`, or sync the exact successful',
|
|
480
|
+
'snapshot already fetched by `npm test` with `node test/run-neumerkel.mjs --cached --update-report`.',
|
|
481
|
+
'`node test/run-neumerkel.mjs --cached --verify-report` verifies the tracked report against that last',
|
|
482
482
|
'successful live snapshot without fetching upstream a second time.',
|
|
483
483
|
'',
|
|
484
484
|
);
|
|
@@ -8,7 +8,7 @@ import { createDefaultRegistry, eyePrologLibraryIndicators, eyePrologNativeLibra
|
|
|
8
8
|
import { assertEqual, assertIncludes, assertNotIncludes } from '../test-style.mjs';
|
|
9
9
|
import { buildConformanceReport, formatConformanceReport } from '../run-conformance-report.mjs';
|
|
10
10
|
import { renderWg17SyntaxStatus } from '../../tools/report-wg17-syntax-coverage.mjs';
|
|
11
|
-
import { parseWg17SyntaxTable } from '../../tools/upgrade-wg17.mjs';
|
|
11
|
+
import { parseWg17SyntaxTable, updateWg17InventoryReferences } from '../../tools/upgrade-wg17.mjs';
|
|
12
12
|
import { executeWg17Item, matchesUpstreamExpectation, readWg17SyntaxFixture } from '../run-wg17.mjs';
|
|
13
13
|
import {
|
|
14
14
|
assertArrayEqual,
|
|
@@ -169,6 +169,18 @@ ${profile}`;
|
|
|
169
169
|
assertEqual(fs.readFileSync(filename, 'utf8'), renderWg17SyntaxStatus(), 'WG17 syntax status');
|
|
170
170
|
},
|
|
171
171
|
},
|
|
172
|
+
{
|
|
173
|
+
name: 'WG17 inventory documentation accepts omitted counts and repairs partial updates',
|
|
174
|
+
run: () => {
|
|
175
|
+
const countFree = 'The vendored WG17 syntax snapshot is intentionally secondary.';
|
|
176
|
+
assertEqual(updateWg17InventoryReferences(countFree, 379), countFree, 'no count required');
|
|
177
|
+
const stale = 'The 366-case vendored WG17 matrix and 365-case WG17 syntax matrix; WG17 matrix has 366 executable cases. An unrelated 366-case suite stays unchanged.';
|
|
178
|
+
const expected = 'The 379-case vendored WG17 matrix and 379-case WG17 syntax matrix; WG17 matrix has 379 executable cases. An unrelated 366-case suite stays unchanged.';
|
|
179
|
+
const updated = updateWg17InventoryReferences(stale, 379);
|
|
180
|
+
assertEqual(updated, expected, 'all stale WG17 counts repaired independently of fixture state');
|
|
181
|
+
assertEqual(updateWg17InventoryReferences(updated, 379), updated, 'retry is idempotent');
|
|
182
|
+
},
|
|
183
|
+
},
|
|
172
184
|
{
|
|
173
185
|
name: 'WG17 upgrader accepts omitted HTML table end tags',
|
|
174
186
|
run: () => {
|
|
@@ -637,7 +649,10 @@ ${profile}`;
|
|
|
637
649
|
const publishIndex = publishWorkflow.indexOf('run: npm publish');
|
|
638
650
|
assertEqual(testIndex >= 0 && testIndex < publishIndex, true, 'publish workflow test gate');
|
|
639
651
|
assertEqual(packIndex >= 0 && packIndex < publishIndex, true, 'publish workflow package gate');
|
|
640
|
-
|
|
652
|
+
assertArrayEqual(Object.keys(pkg.scripts).sort(), ['benchmark', 'conformance:update:wg17', 'generate', 'postversion', 'preversion', 'test'], 'small npm command surface');
|
|
653
|
+
assertEqual(pkg.scripts.test, 'node test/run-all.mjs', 'full release gate');
|
|
654
|
+
const runner = fs.readFileSync(path.join(packageRoot, 'test', 'run-all.mjs'), 'utf8');
|
|
655
|
+
assertIncludes(runner, 'runOpenRuleBenchChecks(reporter)', 'OpenRuleBench remains in release gate');
|
|
641
656
|
},
|
|
642
657
|
},
|
|
643
658
|
{
|
|
@@ -123,17 +123,13 @@ export function runNeumerkelHarnessTests(reporter = new TestReporter()) {
|
|
|
123
123
|
reporter.test('release workflow reuses the successful live snapshot instead of refetching', () => {
|
|
124
124
|
const pkg = JSON.parse(fs.readFileSync(path.join(packageRoot, 'package.json'), 'utf8'));
|
|
125
125
|
const scripts = pkg.scripts ?? {};
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
}
|
|
129
|
-
if (scripts['conformance:check:neumerkel'] !== 'node test/run-neumerkel.mjs --cached --verify-report') {
|
|
130
|
-
throw new Error('Neumerkel report check must not refetch live upstream');
|
|
131
|
-
}
|
|
132
|
-
if (!String(scripts.preversion ?? '').includes('conformance:sync:neumerkel')) {
|
|
126
|
+
const releaseSteps = String(scripts.preversion ?? '').split(' && ');
|
|
127
|
+
if (releaseSteps[0] !== 'npm test' || releaseSteps[1] !== 'node test/run-neumerkel.mjs --cached --update-report') {
|
|
133
128
|
throw new Error('preversion must synchronize the tracked report from the successful npm test snapshot');
|
|
134
129
|
}
|
|
135
|
-
if (
|
|
136
|
-
|
|
130
|
+
if (releaseSteps[2] !== 'node test/run-conformance-report.mjs conformance-report.md' ||
|
|
131
|
+
releaseSteps[3] !== 'git add test/conformance/NEUMERKEL-LATEST.md conformance-report.md' || releaseSteps.length !== 4) {
|
|
132
|
+
throw new Error('preversion must generate and stage both reports without another fetch');
|
|
137
133
|
}
|
|
138
134
|
});
|
|
139
135
|
|
package/test/run-neumerkel.mjs
CHANGED
|
@@ -29,7 +29,7 @@ function parseArgs(argv) {
|
|
|
29
29
|
|
|
30
30
|
function printHelp() {
|
|
31
31
|
process.stdout.write(
|
|
32
|
-
'Usage:
|
|
32
|
+
'Usage: node test/run-neumerkel.mjs [--cached] [--source-dir DIR] [--verify-report] [--update-report]\n\n' +
|
|
33
33
|
'Default: fetch all seven current Neumerkel conformity sources live and run\n' +
|
|
34
34
|
'every discovered case. A stale tracked report is reported as a warning, not\n' +
|
|
35
35
|
'an engine-test failure. --verify-report makes report freshness mandatory;\n' +
|
|
@@ -54,7 +54,7 @@ export async function runNeumerkel(reporter, options = {}) {
|
|
|
54
54
|
if (committed !== result.reportText) {
|
|
55
55
|
const message =
|
|
56
56
|
`tracked Neumerkel report is stale: ${relativeReportPath}\n` +
|
|
57
|
-
'Run
|
|
57
|
+
'Run node test/run-neumerkel.mjs --update-report and commit the updated report.';
|
|
58
58
|
if (effective.verifyReport) throw new Error(message);
|
|
59
59
|
reporter.stdout.write(`WARN ${message}\n`);
|
|
60
60
|
} else {
|
package/the-art-of-eyeprolog.md
CHANGED
|
@@ -7034,7 +7034,7 @@ library dependency should be explicit. `--iso-strict` always disables EyeProlog
|
|
|
7034
7034
|
library autoloading, so strict ISO execution never gains procedures from this
|
|
7035
7035
|
implementation convenience.
|
|
7036
7036
|
|
|
7037
|
-
`-w` / `--warnings` reports explicit dependencies on non-profile libraries and calls to non-profile predicates from otherwise common modules. `--portable` turns those diagnostics into a failing run, making the conservative profile suitable for continuous integration. Cross-engine portability can be exercised with `
|
|
7037
|
+
`-w` / `--warnings` reports explicit dependencies on non-profile libraries and calls to non-profile predicates from otherwise common modules. `--portable` turns those diagnostics into a failing run, making the conservative profile suitable for continuous integration. Cross-engine portability can be exercised with `node test/run-interop.mjs` when EyeProlog, Trealla, and Scryer are installed.
|
|
7038
7038
|
|
|
7039
7039
|
### Specialized library implementation notes
|
|
7040
7040
|
|
|
@@ -10339,7 +10339,7 @@ hand.
|
|
|
10339
10339
|
Run all 210 normal answer goldens and the 61 selected proof goldens with:
|
|
10340
10340
|
|
|
10341
10341
|
```sh
|
|
10342
|
-
|
|
10342
|
+
node test/run-examples.mjs
|
|
10343
10343
|
```
|
|
10344
10344
|
|
|
10345
10345
|
Run the complete conformance, regression, example, and proof corpus
|
|
@@ -10354,8 +10354,8 @@ and fast:
|
|
|
10354
10354
|
|
|
10355
10355
|
```sh
|
|
10356
10356
|
npm run benchmark
|
|
10357
|
-
npm run benchmark
|
|
10358
|
-
|
|
10357
|
+
npm run benchmark -- --save .benchmarks/baseline.json
|
|
10358
|
+
node test/lips-benchmark.mjs
|
|
10359
10359
|
```
|
|
10360
10360
|
|
|
10361
10361
|
The benchmark suite contains 19 representative workloads and stores their
|
|
@@ -10368,7 +10368,7 @@ warm-up batch, five measured batches are reported as milliseconds per workload
|
|
|
10368
10368
|
execution. Naturally long workloads keep a batch size of one.
|
|
10369
10369
|
|
|
10370
10370
|
The classic `examples/bench.pl` workload also has a dedicated LIPS harness.
|
|
10371
|
-
`
|
|
10371
|
+
`node test/lips-benchmark.mjs` follows the 1984 Quintus method more closely than the
|
|
10372
10372
|
generic runner: `dobench/1` and `dodummy/1` execute failure-driven loops inside
|
|
10373
10373
|
Prolog, the dummy CPU time is subtracted, and the remaining time is converted
|
|
10374
10374
|
using 496 procedure calls for one reversal of the 30-element list. Node's
|
|
@@ -10409,9 +10409,9 @@ lists, terms, atoms, variables, negation, queries, rules, and
|
|
|
10409
10409
|
syntax. Separate corpora cover expected errors, warnings, and proofs:
|
|
10410
10410
|
|
|
10411
10411
|
```sh
|
|
10412
|
-
|
|
10413
|
-
|
|
10414
|
-
|
|
10412
|
+
node test/run-conformance-all.mjs
|
|
10413
|
+
node test/run-iso-strict.mjs
|
|
10414
|
+
node test/run-wg17.mjs
|
|
10415
10415
|
node test/run-conformance-report.mjs
|
|
10416
10416
|
```
|
|
10417
10417
|
|
|
@@ -10452,7 +10452,7 @@ The repository exposes several forms of executable evidence:
|
|
|
10452
10452
|
Run the browser contract independently with:
|
|
10453
10453
|
|
|
10454
10454
|
```sh
|
|
10455
|
-
|
|
10455
|
+
node test/run-playground.mjs
|
|
10456
10456
|
```
|
|
10457
10457
|
|
|
10458
10458
|
### Supported ISO Prolog implementation
|
|
@@ -97,7 +97,7 @@ const text = `// Generated by tools/generate-library-autoload-index.mjs.\n` +
|
|
|
97
97
|
if (process.argv.includes('--check')) {
|
|
98
98
|
const current = fs.existsSync(outputFile) ? fs.readFileSync(outputFile, 'utf8') : '';
|
|
99
99
|
if (current !== text) {
|
|
100
|
-
console.error(`${path.relative(root, outputFile)} is stale; run npm run generate
|
|
100
|
+
console.error(`${path.relative(root, outputFile)} is stale; run npm run generate`);
|
|
101
101
|
process.exit(1);
|
|
102
102
|
}
|
|
103
103
|
console.log(`${path.relative(root, outputFile)} is up to date`);
|
|
@@ -209,7 +209,7 @@ const wanted = expectedBook(book, generated);
|
|
|
209
209
|
|
|
210
210
|
if (process.argv.includes('--check')) {
|
|
211
211
|
if (wanted !== book) {
|
|
212
|
-
console.error(`${path.relative(root, bookFile)} predicate reference is stale; run npm run generate
|
|
212
|
+
console.error(`${path.relative(root, bookFile)} predicate reference is stale; run npm run generate`);
|
|
213
213
|
process.exit(1);
|
|
214
214
|
}
|
|
215
215
|
console.log(`${path.relative(root, bookFile)} predicate reference is up to date (${surface.indicators.length} predicates)`);
|
|
@@ -134,9 +134,9 @@ ${untracedIds.length === 0 ? 'None.' : `${formatRanges(untracedIds)}.`}
|
|
|
134
134
|
|
|
135
135
|
## Maintenance
|
|
136
136
|
|
|
137
|
-
1. Run \`npm run conformance:update\` to reconcile the dated fixture with upstream.
|
|
137
|
+
1. Run \`npm run conformance:update:wg17\` to reconcile the dated fixture with upstream.
|
|
138
138
|
2. Review every new or changed ISO expectation before adding its expected outcome.
|
|
139
|
-
3. Run \`
|
|
139
|
+
3. Run \`node test/run-wg17.mjs\` and keep this generated status page synchronized.
|
|
140
140
|
`;
|
|
141
141
|
}
|
|
142
142
|
|
|
@@ -158,7 +158,7 @@ if (process.argv[1] != null && path.resolve(process.argv[1]) === fileURLToPath(i
|
|
|
158
158
|
if (process.argv.includes('--check')) {
|
|
159
159
|
const current = fs.readFileSync(statusPath, 'utf8');
|
|
160
160
|
if (current !== rendered) {
|
|
161
|
-
process.stderr.write('WG17 syntax status is stale; run npm run conformance:update and update the file.\n');
|
|
161
|
+
process.stderr.write('WG17 syntax status is stale; run npm run conformance:update:wg17 and update the file.\n');
|
|
162
162
|
process.exitCode = 1;
|
|
163
163
|
}
|
|
164
164
|
} else {
|
package/tools/upgrade-wg17.mjs
CHANGED
|
@@ -396,17 +396,20 @@ function formatIdList(ids) {
|
|
|
396
396
|
return ids.length === 0 ? 'none' : ids.map((id) => `#${id}`).join(', ');
|
|
397
397
|
}
|
|
398
398
|
|
|
399
|
-
function
|
|
400
|
-
|
|
399
|
+
export function updateWg17InventoryReferences(text, nextCount) {
|
|
400
|
+
// Some documents deliberately omit a count. Update only explicit WG17
|
|
401
|
+
// inventory references, independently of the previous fixture count: a
|
|
402
|
+
// retry may follow a partial update that already wrote the new fixture.
|
|
403
|
+
return text
|
|
404
|
+
.replace(/\b\d+-case(?=\s+(?:vendored\s+)?WG17\b)/g, `${nextCount}-case`)
|
|
405
|
+
.replace(/\bWG17 matrix has \d+ executable/g, `WG17 matrix has ${nextCount} executable`);
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
function updateDocumentedInventoryCount(nextCount) {
|
|
401
409
|
for (const filename of countDocumentationPaths) {
|
|
402
410
|
const original = fs.readFileSync(filename, 'utf8');
|
|
403
|
-
const updated = original
|
|
404
|
-
|
|
405
|
-
.replaceAll(`WG17 matrix has ${previousCount} executable`, `WG17 matrix has ${nextCount} executable`);
|
|
406
|
-
if (updated === original) {
|
|
407
|
-
throw new Error(`WG17 inventory count was not found in ${path.relative(packageRoot, filename)}`);
|
|
408
|
-
}
|
|
409
|
-
fs.writeFileSync(filename, updated);
|
|
411
|
+
const updated = updateWg17InventoryReferences(original, nextCount);
|
|
412
|
+
if (updated !== original) fs.writeFileSync(filename, updated);
|
|
410
413
|
}
|
|
411
414
|
}
|
|
412
415
|
|
|
@@ -454,7 +457,7 @@ function parseArgs(argv) {
|
|
|
454
457
|
}
|
|
455
458
|
|
|
456
459
|
function printHelp() {
|
|
457
|
-
process.stdout.write(`Usage: npm run conformance:update -- [--check] [--source URL_OR_FILE]\n\n` +
|
|
460
|
+
process.stdout.write(`Usage: npm run conformance:update:wg17 -- [--check] [--source URL_OR_FILE]\n\n` +
|
|
458
461
|
`Refreshes the vendored WG17 conformity tests from the TU Wien table.\n` +
|
|
459
462
|
`New or changed rows are executable immediately against the upstream\n` +
|
|
460
463
|
`Codex expectation; existing reviewed exact outcomes remain pinned only as additional regression checks.\n`);
|
|
@@ -474,7 +477,7 @@ export async function upgradeWg17({ check = false, source = syntaxSource } = {})
|
|
|
474
477
|
|
|
475
478
|
if (check) {
|
|
476
479
|
if (semanticChanges > 0) {
|
|
477
|
-
process.stderr.write('WG17 snapshot is stale; run npm run conformance:update.\n');
|
|
480
|
+
process.stderr.write('WG17 snapshot is stale; run npm run conformance:update:wg17.\n');
|
|
478
481
|
process.exitCode = 1;
|
|
479
482
|
return { changed: true, ...reconciliation };
|
|
480
483
|
}
|
|
@@ -507,7 +510,7 @@ export async function upgradeWg17({ check = false, source = syntaxSource } = {})
|
|
|
507
510
|
// Generate status after the fixture/manifest are synchronized.
|
|
508
511
|
const { renderWg17SyntaxStatus } = await import('./report-wg17-syntax-coverage.mjs');
|
|
509
512
|
fs.writeFileSync(syntaxStatusPath, renderWg17SyntaxStatus());
|
|
510
|
-
updateDocumentedInventoryCount(
|
|
513
|
+
updateDocumentedInventoryCount(fixture.cases.length);
|
|
511
514
|
|
|
512
515
|
// The public report executes the refreshed fixture, so keep its measured row
|
|
513
516
|
// synchronized as part of the same explicit upgrade operation.
|
|
@@ -521,7 +524,7 @@ export async function upgradeWg17({ check = false, source = syntaxSource } = {})
|
|
|
521
524
|
process.stdout.write(`Updated WG17 snapshot (${fixture.cases.length} cases).\n`);
|
|
522
525
|
if (upstreamAssertions.length > 0) {
|
|
523
526
|
process.stdout.write(
|
|
524
|
-
`Direct upstream assertions used by
|
|
527
|
+
`Direct upstream assertions used by the WG17 runner: ${formatIdList(upstreamAssertions)}\n`,
|
|
525
528
|
);
|
|
526
529
|
}
|
|
527
530
|
return { changed: semanticChanges > 0, upstreamAssertions, ...reconciliation };
|