eyeprolog 1.4.0 → 1.4.1
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 +1 -1
- package/conformance-report.md +15 -1
- package/package.json +1 -1
- package/test/conformance/ISO-COMPLIANCE.md +1 -1
- package/test/conformance/README.md +3 -3
- package/test/run-conformance-report.mjs +79 -12
- package/test/run-regression.mjs +17 -0
- package/the-art-of-eyeprolog.md +3 -3
package/README.md
CHANGED
|
@@ -68,7 +68,7 @@ printf 'human(socrates).\nmortal(X) :- human(X).\n' |
|
|
|
68
68
|
- [Symbiotic Knowledge Graphs](examples/deck/symbiotic-knowledge-graphs.md) — RDF ↔ Prolog heatwave-response demo for human/AI/KG co-evolution
|
|
69
69
|
- [rdf-prolog-roundtrip](https://github.com/eyereasoner/rdf-prolog-roundtrip) — standalone RDF 1.2 ↔ ISO Prolog bridge used by the RDF examples
|
|
70
70
|
- [ISO conformance audit](test/conformance/ISO-COMPLIANCE.md) — supported Part 1 profile
|
|
71
|
-
- [Conformance report](conformance-report.md) — generated
|
|
71
|
+
- [Conformance report](conformance-report.md) — generated executable conformance status and corpus summary
|
|
72
72
|
- [OpenRuleBench](openrulebench/README.md) — portable benchmark profile
|
|
73
73
|
|
|
74
74
|
## RDF, Prolog, and symbiotic knowledge graphs
|
package/conformance-report.md
CHANGED
|
@@ -1,6 +1,20 @@
|
|
|
1
1
|
# EyeProlog conformance report
|
|
2
2
|
|
|
3
|
-
This report
|
|
3
|
+
This report combines an executable external conformance gate with the file-based
|
|
4
|
+
conformance corpus under `test/conformance/`. The executable result is measured
|
|
5
|
+
when this report is generated; it is not inferred from fixture counts.
|
|
6
|
+
|
|
7
|
+
## Executable conformance status
|
|
8
|
+
|
|
9
|
+
| Gate | Passed | Total | Status |
|
|
10
|
+
|---|---:|---:|---|
|
|
11
|
+
| WG17 syntax | 366 | 366 | pass |
|
|
12
|
+
|
|
13
|
+
The WG17 syntax row executes the vendored 366-case conformity-testing matrix
|
|
14
|
+
against EyeProlog's strict ISO reader/writer. A behavior fix such as operator-token
|
|
15
|
+
spelling therefore changes this report even when no corpus file is added or removed.
|
|
16
|
+
|
|
17
|
+
## File-based corpus inventory
|
|
4
18
|
|
|
5
19
|
| Category | Positive | Errors | Warnings | Proofs | Total |
|
|
6
20
|
|---|---:|---:|---:|---:|---:|
|
package/package.json
CHANGED
|
@@ -6,7 +6,7 @@ together with Technical Corrigenda 1:2007, 2:2012, and 3:2017. Detailed
|
|
|
6
6
|
row-level evidence lives only where it adds information: the built-in, processor,
|
|
7
7
|
term-semantics, Prolog-text/execution, evaluable-functor, implementation-defined,
|
|
8
8
|
WG17-syntax, and STC draft ledgers in this directory. The generated
|
|
9
|
-
[`conformance-report.md`](../../conformance-report.md) gives current case totals.
|
|
9
|
+
[`conformance-report.md`](../../conformance-report.md) gives the current executable WG17 syntax result together with file-based case totals.
|
|
10
10
|
|
|
11
11
|
The ledger deliberately does **not** claim independent certification. A row
|
|
12
12
|
marked `covered` means EyeProlog has implementation and executable tests for
|
|
@@ -109,7 +109,7 @@ terminating newline, so stream-sensitive cases such as #270 and #271 exercise
|
|
|
109
109
|
the characters left after `read/1`. Normal `npm test` remains offline and uses
|
|
110
110
|
only the committed upstream snapshot.
|
|
111
111
|
|
|
112
|
-
|
|
112
|
+
Regenerate the public conformance report, including the executable WG17 syntax status and the file-based category inventory:
|
|
113
113
|
|
|
114
114
|
```sh
|
|
115
115
|
node test/run-conformance-report.mjs
|
|
@@ -146,8 +146,8 @@ are recorded in [THIRD_PARTY.md](THIRD_PARTY.md).
|
|
|
146
146
|
The corpus has 386 cases in `iso/` and 802 file-based conformance cases in
|
|
147
147
|
total. Of those, 11 cases in `stc/` are explicitly labelled working-draft
|
|
148
148
|
review evidence rather than normative ISO claims. The separate strict-reader WG17 matrix has 366 executable dispositions.
|
|
149
|
-
The generated `conformance-report.md` is the authoritative source for current
|
|
150
|
-
category totals. Together with regression, documentation-sync, API, example,
|
|
149
|
+
The generated `conformance-report.md` is the authoritative source for the current
|
|
150
|
+
executable WG17 syntax result and file-based category totals. Together with regression, documentation-sync, API, example,
|
|
151
151
|
and book-example checks, `npm test` is the release gate.
|
|
152
152
|
|
|
153
153
|
## Updating expected output
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
2
|
+
// Executable conformance status plus static corpus inventory.
|
|
3
|
+
// The WG17 row is run when this report is generated, so a syntax-conformance
|
|
4
|
+
// regression changes the public report even when the fixture inventory itself
|
|
5
|
+
// has not changed.
|
|
5
6
|
import fs from 'node:fs';
|
|
6
7
|
import path from 'node:path';
|
|
7
8
|
import { fileURLToPath } from 'node:url';
|
|
9
|
+
import { runWg17 } from './run-wg17.mjs';
|
|
8
10
|
import { listPrologFiles } from './test-support.mjs';
|
|
9
11
|
|
|
10
12
|
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)));
|
|
@@ -18,9 +20,9 @@ const KINDS = [
|
|
|
18
20
|
{ kind: 'proofs', expectedKind: 'expected-proofs', expectedExt: '.pl', column: 'proofs' },
|
|
19
21
|
];
|
|
20
22
|
|
|
21
|
-
export function buildConformanceReport() {
|
|
23
|
+
export function buildConformanceReport({ wg17Suite = runWg17 } = {}) {
|
|
22
24
|
const categories = new Map();
|
|
23
|
-
const
|
|
25
|
+
const corpusIssues = [];
|
|
24
26
|
|
|
25
27
|
for (const { kind, expectedKind, expectedExt, column } of KINDS) {
|
|
26
28
|
const base = path.join(conformanceRoot, kind);
|
|
@@ -33,10 +35,10 @@ export function buildConformanceReport() {
|
|
|
33
35
|
|
|
34
36
|
const stem = file.slice(0, -3);
|
|
35
37
|
const expected = path.join(conformanceRoot, expectedKind, `${stem}${expectedExt}`);
|
|
36
|
-
if (!fs.existsSync(expected))
|
|
38
|
+
if (!fs.existsSync(expected)) corpusIssues.push(`missing ${expectedKind}/${stem}${expectedExt}`);
|
|
37
39
|
if (kind === 'warnings') {
|
|
38
40
|
const expectedStderr = path.join(conformanceRoot, expectedKind, `${stem}.txt`);
|
|
39
|
-
if (!fs.existsSync(expectedStderr))
|
|
41
|
+
if (!fs.existsSync(expectedStderr)) corpusIssues.push(`missing ${expectedKind}/${stem}.txt`);
|
|
40
42
|
}
|
|
41
43
|
}
|
|
42
44
|
}
|
|
@@ -52,32 +54,97 @@ export function buildConformanceReport() {
|
|
|
52
54
|
total: acc.total + row.total,
|
|
53
55
|
}), { positive: 0, errors: 0, warnings: 0, proofs: 0, total: 0 });
|
|
54
56
|
|
|
55
|
-
|
|
57
|
+
const executable = [executeGate('WG17 syntax', wg17Suite)];
|
|
58
|
+
const executionIssues = executable.flatMap((gate) => gate.failures.map((failure) =>
|
|
59
|
+
`${gate.name}: ${failure.name}: ${failure.message}`));
|
|
60
|
+
|
|
61
|
+
return {
|
|
62
|
+
rows,
|
|
63
|
+
total,
|
|
64
|
+
executable,
|
|
65
|
+
corpusIssues: corpusIssues.sort(),
|
|
66
|
+
executionIssues,
|
|
67
|
+
issues: [...corpusIssues.sort(), ...executionIssues],
|
|
68
|
+
};
|
|
56
69
|
}
|
|
57
70
|
|
|
58
71
|
export function formatConformanceReport(report = buildConformanceReport()) {
|
|
59
72
|
const lines = [
|
|
60
73
|
'# EyeProlog conformance report',
|
|
61
74
|
'',
|
|
62
|
-
'This report
|
|
75
|
+
'This report combines an executable external conformance gate with the file-based',
|
|
76
|
+
'conformance corpus under `test/conformance/`. The executable result is measured',
|
|
77
|
+
'when this report is generated; it is not inferred from fixture counts.',
|
|
78
|
+
'',
|
|
79
|
+
'## Executable conformance status',
|
|
80
|
+
'',
|
|
81
|
+
'| Gate | Passed | Total | Status |',
|
|
82
|
+
'|---|---:|---:|---|',
|
|
83
|
+
];
|
|
84
|
+
|
|
85
|
+
for (const gate of report.executable) {
|
|
86
|
+
const status = gate.passed === gate.total ? 'pass' : 'fail';
|
|
87
|
+
lines.push(`| ${gate.name} | ${gate.passed} | ${gate.total} | ${status} |`);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
lines.push(
|
|
91
|
+
'',
|
|
92
|
+
'The WG17 syntax row executes the vendored 366-case conformity-testing matrix',
|
|
93
|
+
'against EyeProlog\'s strict ISO reader/writer. A behavior fix such as operator-token',
|
|
94
|
+
'spelling therefore changes this report even when no corpus file is added or removed.',
|
|
95
|
+
'',
|
|
96
|
+
'## File-based corpus inventory',
|
|
63
97
|
'',
|
|
64
98
|
'| Category | Positive | Errors | Warnings | Proofs | Total |',
|
|
65
99
|
'|---|---:|---:|---:|---:|---:|',
|
|
66
|
-
|
|
100
|
+
);
|
|
67
101
|
|
|
68
102
|
for (const row of report.rows) {
|
|
69
103
|
lines.push(`| ${row.category} | ${row.positive} | ${row.errors} | ${row.warnings} | ${row.proofs} | ${row.total} |`);
|
|
70
104
|
}
|
|
71
105
|
lines.push(`| **Total** | **${report.total.positive}** | **${report.total.errors}** | **${report.total.warnings}** | **${report.total.proofs}** | **${report.total.total}** |`);
|
|
72
106
|
|
|
73
|
-
if (report.
|
|
107
|
+
if (report.corpusIssues.length > 0) {
|
|
74
108
|
lines.push('', '## Corpus issues', '');
|
|
75
|
-
for (const issue of report.
|
|
109
|
+
for (const issue of report.corpusIssues) lines.push(`- ${issue}`);
|
|
110
|
+
}
|
|
111
|
+
if (report.executionIssues.length > 0) {
|
|
112
|
+
lines.push('', '## Executable conformance failures', '');
|
|
113
|
+
for (const issue of report.executionIssues) lines.push(`- ${issue}`);
|
|
76
114
|
}
|
|
77
115
|
|
|
78
116
|
return `${lines.join('\n')}\n`;
|
|
79
117
|
}
|
|
80
118
|
|
|
119
|
+
function executeGate(name, runSuite) {
|
|
120
|
+
const failures = [];
|
|
121
|
+
const reporter = {
|
|
122
|
+
passed: 0,
|
|
123
|
+
total: 0,
|
|
124
|
+
section() {},
|
|
125
|
+
sectionTotal() {},
|
|
126
|
+
test(testName, run) {
|
|
127
|
+
this.total++;
|
|
128
|
+
try {
|
|
129
|
+
run();
|
|
130
|
+
this.passed++;
|
|
131
|
+
} catch (error) {
|
|
132
|
+
failures.push({
|
|
133
|
+
name: testName,
|
|
134
|
+
message: String(error?.message ?? error).split('\n', 1)[0],
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
try {
|
|
141
|
+
runSuite(reporter);
|
|
142
|
+
} catch (error) {
|
|
143
|
+
failures.push({ name: 'suite setup', message: String(error?.message ?? error).split('\n', 1)[0] });
|
|
144
|
+
}
|
|
145
|
+
return { name, passed: reporter.passed, total: reporter.total, failures };
|
|
146
|
+
}
|
|
147
|
+
|
|
81
148
|
function categoryOf(file) {
|
|
82
149
|
const parts = file.split('/');
|
|
83
150
|
return parts.length > 1 ? parts[0] : 'legacy-numbered';
|
package/test/run-regression.mjs
CHANGED
|
@@ -5029,10 +5029,27 @@ function documentationSyncCases() {
|
|
|
5029
5029
|
assertEqual(report.total.total >= 475, true, 'conformance case count');
|
|
5030
5030
|
assertEqual(report.total.positive + report.total.errors + report.total.warnings + report.total.proofs, report.total.total, 'conformance total');
|
|
5031
5031
|
assertEqual(report.rows.some((row) => row.category === 'legacy-numbered'), false, 'legacy-numbered category');
|
|
5032
|
+
const wg17 = report.executable.find((gate) => gate.name === 'WG17 syntax');
|
|
5033
|
+
assertEqual(wg17?.total, 366, 'WG17 executable total');
|
|
5034
|
+
assertEqual(wg17?.passed, 366, 'WG17 executable passed');
|
|
5035
|
+
assertArrayEqual(wg17?.failures ?? [], [], 'WG17 executable failures');
|
|
5032
5036
|
const text = formatConformanceReport(report);
|
|
5037
|
+
assertIncludes(text, '| WG17 syntax | 366 | 366 | pass |', 'report');
|
|
5033
5038
|
assertIncludes(text, '| variables |', 'report');
|
|
5034
5039
|
assertIncludes(text, '| Proofs |', 'report');
|
|
5035
5040
|
assertIncludes(text, '| **Total** |', 'report');
|
|
5041
|
+
|
|
5042
|
+
const failing = buildConformanceReport({
|
|
5043
|
+
wg17Suite: (reporter) => {
|
|
5044
|
+
reporter.section('WG17 syntax');
|
|
5045
|
+
reporter.test('synthetic syntax failure', () => { throw new Error('synthetic mismatch'); });
|
|
5046
|
+
reporter.sectionTotal('WG17 syntax');
|
|
5047
|
+
},
|
|
5048
|
+
});
|
|
5049
|
+
assertEqual(failing.executable[0].passed, 0, 'failing WG17 executable passed');
|
|
5050
|
+
assertEqual(failing.executable[0].total, 1, 'failing WG17 executable total');
|
|
5051
|
+
assertEqual(failing.executionIssues.length, 1, 'failing WG17 report issue count');
|
|
5052
|
+
assertIncludes(formatConformanceReport(failing), '| WG17 syntax | 0 | 1 | fail |', 'failing report');
|
|
5036
5053
|
},
|
|
5037
5054
|
},
|
|
5038
5055
|
|
package/the-art-of-eyeprolog.md
CHANGED
|
@@ -7784,14 +7784,14 @@ their declared goals are executed. The eight-case
|
|
|
7784
7784
|
playground contract suite imports the production worker, sends real reasoning
|
|
7785
7785
|
requests through its message protocol, and crawls the served module graph for
|
|
7786
7786
|
missing assets, bad MIME types, and static Node-only imports. The generated
|
|
7787
|
-
`conformance-report.md` is the authoritative source for current
|
|
7788
|
-
category totals.
|
|
7787
|
+
`conformance-report.md` is the authoritative source for the current executable
|
|
7788
|
+
WG17 syntax result and file-based conformance category totals.
|
|
7789
7789
|
|
|
7790
7790
|
### Generated and checked repository material
|
|
7791
7791
|
|
|
7792
7792
|
Repository artifacts have distinct roles:
|
|
7793
7793
|
|
|
7794
|
-
- `conformance-report.md`
|
|
7794
|
+
- `conformance-report.md` executes the vendored WG17 syntax gate and also inventories the file-based conformance corpus;
|
|
7795
7795
|
- `examples/book/` is extracted from executable code blocks in this book and
|
|
7796
7796
|
should be rebuilt with `npm run generate` rather than edited directly;
|
|
7797
7797
|
- `examples/output/` and `examples/proof/` contain reviewed exact-output
|