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 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 public corpus summary
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
@@ -1,6 +1,20 @@
1
1
  # EyeProlog conformance report
2
2
 
3
- This report summarizes the file-based conformance corpus under `test/conformance/`.
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
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "1.4.0",
6
+ "version": "1.4.1",
7
7
  "description": "EyeProlog turns facts and rules into answers and proofs.",
8
8
  "type": "module",
9
9
  "main": "./index.js",
@@ -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
- Summarize conformance coverage by category:
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
- // Static conformance corpus report.
3
- // This complements the executable runner with a category summary that makes
4
- // coverage growth visible without running every case.
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 issues = [];
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)) issues.push(`missing ${expectedKind}/${stem}${expectedExt}`);
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)) issues.push(`missing ${expectedKind}/${stem}.txt`);
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
- return { rows, total, issues: issues.sort() };
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 summarizes the file-based conformance corpus under `test/conformance/`.',
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.issues.length > 0) {
107
+ if (report.corpusIssues.length > 0) {
74
108
  lines.push('', '## Corpus issues', '');
75
- for (const issue of report.issues) lines.push(`- ${issue}`);
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';
@@ -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
 
@@ -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 conformance
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` is generated from the file-based conformance corpus;
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