eyeprolog 1.5.17 → 1.5.19

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/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "1.5.17",
6
+ "version": "1.5.19",
7
7
  "description": "EyeProlog turns facts and rules into answers and proofs.",
8
8
  "type": "module",
9
9
  "main": "./index.js",
@@ -188,6 +188,11 @@ function writeOptions(term, env, solver) {
188
188
  else if (option.name === 'double_quotes' && !solver.isoStrict) result.doubleQuotes = optionBoolean(option.args[0], env, option);
189
189
  else throw new PrologError('domain_error(write_option)', copyResolved(option, env));
190
190
  }
191
+ if (result.doubleQuotes === true) {
192
+ result.doubleQuotes = solver.prologFlags.get('double_quotes')?.value?.name ?? 'chars';
193
+ } else {
194
+ result.doubleQuotes = null;
195
+ }
191
196
  return result;
192
197
  }
193
198
 
package/src/write.js CHANGED
@@ -334,7 +334,11 @@ function format(term, env, options, table, maxPriority = 1200, context = 'term')
334
334
  }
335
335
  }
336
336
 
337
- if (!options.ignoreOps && isCons(resolved)) {
337
+ if (isCons(resolved)) {
338
+ // double_quotes/1 selects a character-list representation independently
339
+ // of operator notation. In normal mode, `||` is fixed list-splice syntax
340
+ // rather than an op/3 declaration, so ignore_ops(true) does not suppress
341
+ // an explicitly requested double-quoted proper or partial character list.
338
342
  const quotedSplice = quotedListSplice(resolved, env, options.doubleQuotes);
339
343
  if (quotedSplice != null && (quotedSplice.tail == null || options.doubleBar)) {
340
344
  const prefix = writeString(quotedSplice.text);
@@ -344,18 +348,21 @@ function format(term, env, options, table, maxPriority = 1200, context = 'term')
344
348
  // emitted text readable as the same term.
345
349
  return `${prefix}||${format(quotedSplice.tail, env, options, table, 1, 'term')}`;
346
350
  }
347
- const parts = [];
348
- let cursor = resolved;
349
- while (true) {
350
- cursor = deref(cursor, env);
351
- const separator = options.compact ? ',' : ', ';
352
- if (isEmptyList(cursor)) return `[${parts.join(separator)}]`;
353
- if (!isCons(cursor)) {
354
- const tailSeparator = options.compact ? '|' : ' | ';
355
- return `[${parts.join(separator)}${tailSeparator}${format(cursor, env, options, table, 999, 'argument')}]`;
351
+
352
+ if (!options.ignoreOps) {
353
+ const parts = [];
354
+ let cursor = resolved;
355
+ while (true) {
356
+ cursor = deref(cursor, env);
357
+ const separator = options.compact ? ',' : ', ';
358
+ if (isEmptyList(cursor)) return `[${parts.join(separator)}]`;
359
+ if (!isCons(cursor)) {
360
+ const tailSeparator = options.compact ? '|' : ' | ';
361
+ return `[${parts.join(separator)}${tailSeparator}${format(cursor, env, options, table, 999, 'argument')}]`;
362
+ }
363
+ parts.push(format(cursor.args[0], env, options, table, 999, 'argument'));
364
+ cursor = cursor.args[1];
356
365
  }
357
- parts.push(format(cursor.args[0], env, options, table, 999, 'argument'));
358
- cursor = cursor.args[1];
359
366
  }
360
367
  }
361
368
 
@@ -124,7 +124,7 @@ families; `--iso-strict` is intended to remove their Part 1 interpretation.
124
124
  | 5.5.9 Built-in predicates | EyeProlog libraries, CLP(Z), statistics, Part 3 `phrase/2-3`, and bundled-library autoloaded predicates | Strict registry contains only the Part 1 + Corrigenda core registry. |
125
125
  | 5.5.10 Evaluable functors | Normal mode additionally accepts the EyeProlog evaluable atom `e`; the remaining arithmetic functors accepted by strict mode are the Part 1 + Corrigenda set. | Strict mode rejects `e/0` as non-evaluable and retains the Corrigendum arithmetic additions. **covered** — strict extension-boundary regression plus `src/iso-arithmetic.js`. |
126
126
  | 5.5.11 Reserved atoms | None | None. |
127
- | Cor.3 5.5.12 Options | Extra library/host options may exist outside core option lists | Normal mode additionally accepts the EyeProlog `write_term/2-3` options `double_quotes(true|false)` and `spacing(true|false)`. `spacing(false)` emits only lexically required separators; `spacing(true)` adds conventional layout around operators. Strict core excludes these implementation-specific extensions and accepts only the Part 1 plus Corrigendum 3 write-option surface; unknown extension options raise `domain_error(write_option,...)`. |
127
+ | Cor.3 5.5.12 Options | Extra library/host options may exist outside core option lists | Normal mode additionally accepts the EyeProlog `write_term/2-3` options `double_quotes(true|false)` and `spacing(true|false)`. `double_quotes(true)` is orthogonal to `ignore_ops(true)`: eligible character/code lists retain double-quoted notation while operator terms use functional notation, and the order of those distinct options does not affect the result. `spacing(false)` emits only lexically required separators; `spacing(true)` adds conventional layout around operators. Strict core excludes these implementation-specific extensions and accepts only the Part 1 plus Corrigendum 3 write-option surface; unknown extension options raise `domain_error(write_option,...)`. |
128
128
 
129
129
  Normal mode provides documented module and DCG compatibility profiles whose
130
130
  features overlap standardized Part 2 and Part 3 facilities. They are extensions
@@ -4797,18 +4797,28 @@ function documentationSyncCases() {
4797
4797
 
4798
4798
  const book = fs.readFileSync(path.join(packageRoot, 'the-art-of-eyeprolog.md'), 'utf8');
4799
4799
  const section = between(book, '<!-- eyeprolog-predicate-reference:start -->', '<!-- eyeprolog-predicate-reference:end -->');
4800
- assertEqual(section.split('\n').some((line) => line.trimStart().startsWith('|')), false, 'predicate reference avoids Markdown tables and horizontal overflow');
4801
- assertEqual((section.match(/^- \*\*`/gm) ?? []).length, 518, 'one stacked reference entry per predicate');
4802
- assertEqual((section.match(/<a id="predicate-reference-\d{4}"><\/a>/g) ?? []).length, 518, 'one explicit stable anchor per predicate');
4800
+ assertEqual(section.split('\n').some((line) => line.trimStart().startsWith('|')), false, 'predicate reference avoids wide table markup');
4801
+ assertEqual((section.match(/^- \*\*`/gm) ?? []).length, 518, 'one reference entry per predicate');
4802
+ assertEqual((section.match(/<a id="predicate-reference-\d{4}"><\/a>/g) ?? []).length, 518, 'one explicit anchor per predicate');
4803
4803
  assertEqual((section.match(/\]\(#predicate-reference-\d{4}\)/g) ?? []).length, 518, 'one direct index link per predicate');
4804
4804
  assertNotIncludes(section, '[Symbols](#predicate-reference-symbols)', 'predicate index does not rely on renderer-generated group anchors');
4805
- assertIncludes(section, 'stable numeric IDs instead of relying on Markdown heading-slug rules', 'renderer-independent predicate anchors');
4806
- assertIncludes(section, 'wrap naturally on narrow screens without horizontal scrolling', 'responsive predicate reference layout');
4807
4805
 
4808
4806
  const chapter = between(book, '## 39. Predicate reference', '## 40. Running EyeProlog: command line and corpus');
4809
- assertEqual(chapter.split('\n').some((line) => line.trimStart().startsWith('|')), false, 'Chapter 39 uses one wrapping stacked layout without Markdown tables');
4807
+ assertEqual(chapter.split('\n').some((line) => line.trimStart().startsWith('|')), false, 'Chapter 39 avoids wide table markup');
4808
+ for (const backstage of [
4809
+ 'stacked layout',
4810
+ 'Markdown tables',
4811
+ 'horizontal scrollbars',
4812
+ 'horizontal scrolling',
4813
+ 'documentation test',
4814
+ 'documentation regression',
4815
+ 'stable numeric IDs',
4816
+ 'generated reference',
4817
+ 'Read the chapter in that order',
4818
+ 'final generated section',
4819
+ ]) assertNotIncludes(chapter, backstage, `Chapter 39 avoids editorial/process prose: ${backstage}`);
4810
4820
  const orderedHeadings = [
4811
- '### How to read this chapter',
4821
+ '### Notation and conventions',
4812
4822
  '### Core registry',
4813
4823
  '### Normal-mode extensions',
4814
4824
  '### Bundled libraries',
@@ -4825,6 +4835,35 @@ function documentationSyncCases() {
4825
4835
  }
4826
4836
  },
4827
4837
  },
4838
+ {
4839
+ name: 'book keeps editorial and build mechanics out of reader-facing prose',
4840
+ run: () => {
4841
+ const book = fs.readFileSync(path.join(packageRoot, 'the-art-of-eyeprolog.md'), 'utf8');
4842
+ for (const backstage of [
4843
+ 'stacked layout',
4844
+ 'Markdown tables',
4845
+ 'horizontal scrollbars',
4846
+ 'horizontal scrolling',
4847
+ 'documentation test',
4848
+ 'documentation regression',
4849
+ 'stable numeric IDs',
4850
+ 'generated reference',
4851
+ 'final generated section',
4852
+ 'Read the chapter in that order',
4853
+ 'after editing the book',
4854
+ 'should be rebuilt with `npm run generate`',
4855
+ 'Keeping these details here',
4856
+ '# Part XII — Development note',
4857
+ '## 46. AI-assisted editing',
4858
+ 'release gate',
4859
+ 'release-facing',
4860
+ '# Refresh the vendored TU Wien WG17 inventory',
4861
+ 'the tables in this chapter',
4862
+ 'The generated [`examples/book/`',
4863
+ ]) assertNotIncludes(book, backstage, `book avoids backstage prose: ${backstage}`);
4864
+ assertIncludes(book, 'Chapters are numbered continuously across eleven parts, from Chapter 1 to Chapter 45.', 'reader-facing chapter count');
4865
+ },
4866
+ },
4828
4867
  {
4829
4868
  name: 'reference docs match explicit tabling and current runtime extensions',
4830
4869
  run: () => {
@@ -4844,7 +4883,7 @@ ${profile}`;
4844
4883
  assertIncludes(book, 'including recursive calls, use depth-first resolution unless the source', 'ordinary recursion is depth-first');
4845
4884
  assertIncludes(book, 'explicitly declares `:- table p/n.`', 'tabling is explicit');
4846
4885
  assertIncludes(book, 'The autoload index covers every', 'generic bundled-library autoload');
4847
- assertIncludes(book, 'interactive top-level query therefore autoloads its canonical', 'REPL autoload');
4886
+ assertIncludes(book, 'interactive top-level query autoloads its canonical bundled provider', 'REPL autoload');
4848
4887
  assertIncludes(book, 'Autoloading therefore supplies', 'autoload syntax boundary');
4849
4888
  assertIncludes(book, 'Residual constraints are part of the displayed answer even when', 'top-level hidden residuals');
4850
4889
  assertIncludes(book, 'EyeProlog normal mode also accepts `:+`', 'Eyelet forward-rule extension');
@@ -7058,6 +7097,51 @@ function whiteBoxCases() {
7058
7097
  }
7059
7098
  },
7060
7099
  },
7100
+ {
7101
+ name: 'double_quotes(true) remains effective with ignore_ops(true) in either option order (issue #88 follow-up)',
7102
+ run: () => {
7103
+ const source = [
7104
+ 'emit :-',
7105
+ ` write_term(f("ab",a+b), [double_quotes(true),ignore_ops(true),quoted(true)]), put_char('|'),`,
7106
+ ` write_term(f("ab",a+b), [ignore_ops(true),double_quotes(true),quoted(true)]), put_char('|'),`,
7107
+ ` write_term("ab"||tail, [double_quotes(true),ignore_ops(true)]), put_char('|'),`,
7108
+ ` write_term("ab"||tail, [ignore_ops(true),double_quotes(true)]), put_char('|'),`,
7109
+ ' write_term("ab", [double_quotes(false),ignore_ops(true)]).',
7110
+ '',
7111
+ ].join('\n');
7112
+ assertEqual(
7113
+ run(source, { goal: 'emit' }).stdout,
7114
+ 'f("ab",+(a,b))|f("ab",+(a,b))|"ab"||tail|"ab"||tail|.(a,.(b,[]))emit.\n',
7115
+ 'write_term option composition',
7116
+ );
7117
+
7118
+ const codesSource = [
7119
+ 'emit_codes :-',
7120
+ ' set_prolog_flag(double_quotes, codes),',
7121
+ ' write_term([97,955], [ignore_ops(true),double_quotes(true)]).',
7122
+ '',
7123
+ ].join('\n');
7124
+ assertEqual(run(codesSource, { goal: 'emit_codes' }).stdout, '"aλ"emit_codes.\n',
7125
+ 'double_quotes(codes) representation');
7126
+ },
7127
+ },
7128
+ {
7129
+ name: 'charsio write_term_to_chars composes double_quotes with ignore_ops',
7130
+ run: () => {
7131
+ const source = [
7132
+ ':- use_module(library(charsio)).',
7133
+ 'answer(A,B) :-',
7134
+ ' write_term_to_chars(f("ab",a+b), [double_quotes(true),ignore_ops(true)], A),',
7135
+ ' write_term_to_chars("ab"||tail, [ignore_ops(true),double_quotes(true)], B).',
7136
+ '',
7137
+ ].join('\n');
7138
+ assertEqual(
7139
+ run(source, { goal: 'answer(A,B)' }).stdout,
7140
+ 'answer("f(\\"ab\\",+(a,b))", "\\"ab\\"||tail").\n',
7141
+ 'charsio output',
7142
+ );
7143
+ },
7144
+ },
7061
7145
  {
7062
7146
  name: 'REPL prints partial character lists with double-bar syntax (issue #88)',
7063
7147
  run: () => {
@@ -17,8 +17,7 @@ the two.
17
17
  This book is also the reference for the EyeProlog implementation. EyeProlog is a
18
18
  standards-based reasoning system: programs use the documented and tested ISO
19
19
  Prolog profile.
20
- Chapters 38–40 define the supported ISO Prolog profile, built-ins, libraries, and execution interface. Chapter 39 describes every supported built-in predicate in detail and also contains a generated compact contract for all **518 distinct predicate indicators** in the normal EyeProlog surface; Chapter 40 documents the command-line interface. The explanatory chapters give the reasoning and operational context
21
- needed to use those details correctly.
20
+ Chapters 38–40 define the supported ISO Prolog profile, predicate surface, libraries, and execution interface. Chapter 39 describes every supported built-in and library predicate, with compact contracts for all **518 distinct predicate indicators** in the normal EyeProlog surface; Chapter 40 documents command-line execution. The explanatory chapters give the reasoning and operational context needed to use those details correctly.
22
21
 
23
22
  Its subject is not syntax alone. A logic program has two inseparable aspects:
24
23
  the relation described by its clauses and the procedure induced when goals are
@@ -114,14 +113,12 @@ require their documented host environment.
114
113
 
115
114
  The best way to read is beside a running interpreter. Before each run, predict
116
115
  the answer; after it, change one fact or query and explain the difference.
117
- Use `npm run generate` after editing the book to refresh the extracted
118
- `examples/book/` files.
119
116
 
120
117
  ### Reading conventions
121
118
 
122
119
  Code displays serve three different purposes:
123
120
 
124
- - an `eyeprolog` block is Prolog source accepted by EyeProlog; complete blocks are extracted under
121
+ - an `eyeprolog` block is Prolog source accepted by EyeProlog; complete blocks also appear under
125
122
  `examples/book/`, although a short block may rely on facts introduced in the
126
123
  surrounding chapter;
127
124
  - a `text` block shows output, a trace, a data shape, or pseudocode and is not
@@ -130,8 +127,8 @@ Code displays serve three different purposes:
130
127
 
131
128
  Top-level programs under [`examples/`](https://github.com/eyereasoner/eyeprolog/tree/main/examples/) are the complete runnable
132
129
  cases. Their exact outputs live under `examples/output/`; selected proof
133
- outputs live under `examples/proof/`. Use the chapter extractions for copying a
134
- particular display and the top-level corpus for end-to-end experiments.
130
+ outputs live under `examples/proof/`. Use `examples/book/` to copy a particular
131
+ display and the top-level corpus for end-to-end experiments.
135
132
 
136
133
  ### The promise of this book
137
134
 
@@ -152,10 +149,7 @@ tricks. By the end, a reader should be able to:
152
149
  That is the stake in the ground: a focused implementation of standard Prolog
153
150
  is enough to teach the large ideas when semantics, execution, and evidence
154
151
  remain visible together.
155
- The implementation is therefore part of the argument. The examples are
156
- programs, the reference chapters are the reference for the running system, and
157
- `npm test` checks the complete code displays, local references, and
158
- built-in index against the source tree.
152
+ The implementation is therefore part of the argument: the examples are executable programs, the reference chapters describe the running system, and proof terms remain available for inspection.
159
153
 
160
154
  ### A working discipline
161
155
 
@@ -242,8 +236,7 @@ making a relationship visible that prose alone would make easy to miss.
242
236
 
243
237
  ## Contents
244
238
 
245
- Chapters are numbered continuously across the twelve parts, from Chapter 1 to
246
- Chapter 46.
239
+ Chapters are numbered continuously across eleven parts, from Chapter 1 to Chapter 45.
247
240
 
248
241
  ### Part I — Relations
249
242
 
@@ -345,12 +338,6 @@ Chapter 45
345
338
 
346
339
  - [45. Checkpoint notes and selected answers](#45-checkpoint-notes-and-selected-answers)
347
340
 
348
- ### Part XII — Development note
349
-
350
- Chapter 46
351
-
352
- - [46. AI-assisted editing](#46-ai-assisted-editing)
353
-
354
341
  ---
355
342
 
356
343
  # Part I — Relations
@@ -4351,9 +4338,7 @@ Before trusting an EyeProlog conclusion, ask:
4351
4338
  9. What counterexample would overturn the model?
4352
4339
  10. Can the result be reconstructed under the same source and theory version?
4353
4340
 
4354
- That ritual is the book in miniature. State a small theory. Ask a precise
4355
- question. Let the machine search. Inspect the witness. Challenge the premises.
4356
- Preserve the proof.
4341
+ That ritual captures the discipline. State a small theory. Ask a precise question. Let the machine search. Inspect the witness. Challenge the premises. Preserve the proof.
4357
4342
 
4358
4343
  **Exercises.**
4359
4344
 
@@ -4428,8 +4413,7 @@ state a claim precisely, derive consequences, seek counterexamples, measure the
4428
4413
  computation, and preserve enough evidence for another person to repeat the
4429
4414
  work.
4430
4415
 
4431
- This Part turns the book's ideas into a daily discipline. It does not add a new
4432
- language feature. It shows how to make theories survive change.
4416
+ The reasoning laboratory turns these ideas into a daily discipline. It adds no new language feature; it shows how to make theories survive change.
4433
4417
 
4434
4418
  ## 31. Testing a theory
4435
4419
 
@@ -4873,7 +4857,7 @@ choice, repaired invariant, and test that would fail if the defect returned.
4873
4857
 
4874
4858
  A pattern is not a copied code fragment. It is a recurring arrangement of
4875
4859
  meaning, representation, and control that solves a named design problem. The
4876
- following patterns summarize the strongest constructions in this book.
4860
+ following patterns summarize recurring constructions that are especially useful in practice.
4877
4861
 
4878
4862
  <figure>
4879
4863
  <img src="book-assets/pattern-selection-map.svg" alt="Six recurring design symptoms point to patterns for meaning, tabling, closed boundaries, finite search, proof-carrying answers, and canonical representation.">
@@ -5498,8 +5482,12 @@ still retained where adjacent graphic tokens would otherwise merge, as in
5498
5482
  `double_quotes(true|false)`: `true` lets eligible character/code lists use the
5499
5483
  current `double_quotes` representation. Proper lists can therefore be written
5500
5484
  as `"text"`, while a partial list such as `[a,b|Tail]` is written as
5501
- `"ab"||Tail`. Strict ISO mode rejects this implementation-specific write
5502
- option. Normal mode also accepts the
5485
+ `"ab"||Tail`. This representation choice is independent of `ignore_ops/1`: with
5486
+ `ignore_ops(true)`, operator terms use functional notation while an explicitly
5487
+ requested character/code list remains double quoted. Thus
5488
+ `write_term(f("ab",a+b),[quoted(true),ignore_ops(true),double_quotes(true)])`
5489
+ emits `f("ab",+(a,b))`. Reversing the two options has the same effect. Strict
5490
+ ISO mode rejects this implementation-specific write option. Normal mode also accepts the
5503
5491
  implementation-specific boolean `spacing(true|false)` option: `false` emits
5504
5492
  only separators required to avoid lexical ambiguity, while `true` adds
5505
5493
  conventional layout around operators. For example,
@@ -5916,21 +5904,11 @@ Queries for predicates with no group follow the known groups.
5916
5904
 
5917
5905
  ## 39. Predicate reference
5918
5906
 
5919
- Chapter 39 documents the normal EyeProlog predicate surface as one coherent
5920
- reference. The surface has two layers: **129 core registry indicators** and
5921
- **389 distinct non-ISO library or normal-extension indicators**. Because
5922
- `phrase/2` and `phrase/3` occur in both layers, their union contains **518
5923
- distinct predicate indicators**.
5907
+ EyeProlog's normal predicate surface has two layers: **129 core registry indicators** and **389 distinct non-ISO library or normal-extension indicators**. Because `phrase/2` and `phrase/3` occur in both layers, their union contains **518 distinct predicate indicators**.
5924
5908
 
5925
- Read the chapter in that order. The core registry comes first because it defines
5926
- the language-level operations available without a library import. The bundled
5927
- library layer then adds reusable relations, followed by the portability and
5928
- implementation boundaries that explain how those libraries behave across
5929
- EyeProlog, Trealla, and Scryer. The final generated section is deliberately a
5930
- lookup index: it gives one compact contract and one stable link for every one of
5931
- the 518 indicators without interrupting the explanatory flow above it.
5909
+ Core predicates are available without a library import. Bundled libraries add reusable relations for collections, constraints, graphs, text, time, cryptography, files, and other domains. Interoperability notes identify the subset shared with Trealla and Scryer, and the complete alphabetical reference gives one compact contract for every indicator.
5932
5910
 
5933
- ### How to read this chapter
5911
+ ### Notation and conventions
5934
5912
 
5935
5913
  The call patterns below use `+` for an argument that must be sufficiently
5936
5914
  instantiated, `-` for a result normally produced by the call, and `?` for an
@@ -5948,12 +5926,6 @@ indicator, EyeProlog uses the source clauses. `false/0` is stricter still and is
5948
5926
  rejected as a source-clause head. Portable programs should avoid every such
5949
5927
  collision because other Prolog systems commonly reject it while loading.
5950
5928
 
5951
- Reference material in this chapter uses a single stacked layout instead of wide
5952
- Markdown tables. A bold term introduces one predicate, role, flag, error form,
5953
- or module; the explanation follows on the same item and wraps normally on narrow
5954
- screens. This keeps the reference usable on phones and avoids horizontal
5955
- scrollbars while preserving copyable predicate indicators.
5956
-
5957
5929
  ### Core registry
5958
5930
 
5959
5931
  EyeProlog's default registry contains the built-ins in its ISO compatibility
@@ -6168,11 +6140,7 @@ non-BMP character. Trailing layout, comments, and other material are rejected;
6168
6140
  bound integers are converted to their canonical decimal spelling, and
6169
6141
  non-finite values are rejected. Equivalent spellings of the same numeric type
6170
6142
  compare by value, preserving the standard conversion round trip, while integer
6171
- and floating-point terms remain distinct. The
6172
- regression gate vendors all 74 numbered cases from Ulrich Neumerkel's contemporary
6173
- `number_chars/2` comparison, including the Cor.2 error-precedence cases;
6174
- `number_codes/2` shares the same numeric parser and has mirrored coverage for
6175
- the recent numeric-syntax regressions.
6143
+ and floating-point terms remain distinct. The numeric conversion behavior follows the 74 numbered cases in Ulrich Neumerkel's contemporary `number_chars/2` comparison, including the Corrigendum 2 error-precedence cases; `number_codes/2` uses the same numeric parser.
6176
6144
 
6177
6145
  #### Streams and unit I/O
6178
6146
 
@@ -6211,7 +6179,7 @@ the beginning. A peek does not mark the stream as past-end.
6211
6179
  - **`write(+Term)`, `write(+Stream,+Term)`** — Writes readable operator notation without quoting atoms merely because quoting would be required for reparsing. Number variables are enabled.
6212
6180
  - **`writeq(+Term)`, `writeq(+Stream,+Term)`** — Like `write`, but quotes atoms when required for unambiguous input syntax.
6213
6181
  - **`write_canonical(+Term)`, `write_canonical(+Stream,+Term)`** — Writes quoted canonical functor notation while ignoring operators and without interpreting *$VAR/1*.
6214
- - **`write_term(+Term,+Options)`, `write_term(+Stream,+Term,+Options)`** — Writes with *quoted(true or false)*, *ignore_ops(true or false)*, *numbervars(true or false)*, and *variable_names([Name=Variable,...])*. Normal mode also supports *double_quotes(true or false)* and *spacing(true or false)*.
6182
+ - **`write_term(+Term,+Options)`, `write_term(+Stream,+Term,+Options)`** — Writes with *quoted(true or false)*, *ignore_ops(true or false)*, *numbervars(true or false)*, and *variable_names([Name=Variable,...])*. Normal mode also supports *double_quotes(true or false)* and *spacing(true or false)*. `double_quotes(true)` remains effective with `ignore_ops(true)`: operator terms are written functionally while eligible character/code lists retain double-quoted notation, independently of option order.
6215
6183
 
6216
6184
  Term input uses the program's current operator table and the same ISO quoted-character
6217
6185
  syntax as source text, including backslash-terminated octal and hexadecimal
@@ -6340,19 +6308,12 @@ only the modules it needs, and
6340
6308
  module exposes p.p.1 through p.p.11 of the
6341
6309
  [working-draft Prologue](https://www.complang.tuwien.ac.at/ulrich/iso-prolog/prologue),
6342
6310
  as a compatibility facade over the canonical `lists`, `between`, `iso_ext`,
6343
- and `freeze` modules. The published Prologue, `call_nth/2`, and `length/2`
6344
- quads are retained as offline regressions. `src/standard-library.js` registers the module sources and explicit module-owned
6345
- host adapters. For example, attributed-variable support lives in
6311
+ and `freeze` modules. `src/standard-library.js` registers the module sources and explicit module-owned host adapters. For example, attributed-variable support lives in
6346
6312
  `src/atts-host.js`, while cryptographic primitives live in `src/crypto-host.js`. Whenever `src/lib/foo.pl` needs a private runtime primitive, that
6347
6313
  primitive is registered from `src/foo-host.js`; pure Prolog libraries deliberately
6348
6314
  have no host file. This keeps character I/O, filesystem access, crypto, timing,
6349
6315
  attributed-variable support, and other runtime bridges with the module that owns
6350
- their public semantics instead of in a compatibility grab bag. Architecture tests
6351
- enforce this ownership and reject the retired `library-host.js` and
6352
- `scryer-compat.js`. Explicit `use_module/1-2`
6353
- loads remain supported; outside strict ISO mode, the bundled-library autoloader
6354
- may also load the canonical owner of any exported `src/lib/` predicate. The
6355
- autoload index is generated from the libraries' `module/2` declarations.
6316
+ their public semantics instead of in a compatibility grab bag. Private runtime adapters remain owned by the module whose public semantics they support; no shared compatibility grab bag participates in library execution. Explicit `use_module/1-2` loads remain supported; outside strict ISO mode, the bundled-library autoloader may also load the canonical owner of any exported `src/lib/` predicate.
6356
6317
  The core registry remains available through `createDefaultRegistry()` and
6357
6318
  `getDefaultRegistry()` for low-level embedding. The stricter Part 1 +
6358
6319
  Corrigenda registry is exposed as `createStrictIsoRegistry()` and
@@ -6710,9 +6671,9 @@ extension_answer(same_shape, true) :-
6710
6671
  EyeProlog keeps four related concepts separate:
6711
6672
 
6712
6673
  - ****ISO core**** — The documented ISO predicate profile built into the processor. No EyeProlog library import is involved.
6713
- - ****EyeProlog library surface**** — Every module and exported predicate listed in the catalog above. Programs normally access these with `use_module/1-2`.
6674
+ - ****EyeProlog library surface**** — Every public module and exported predicate in the bundled library layer. Programs normally access these with `use_module/1-2`.
6714
6675
  - ****Interoperability profile**** — A deliberately smaller set of library names and predicate interfaces that EyeProlog intends to keep source-compatible with Trealla and Scryer where practical.
6715
- - ****Autoload index**** — A generated index of every predicate exported by the bundled `src/lib/` modules, with one canonical provider per unambiguous predicate.
6676
+ - ****Autoload surface**** — Every bundled predicate with one canonical provider per unambiguous indicator.
6716
6677
 
6717
6678
  These layers answer different questions. A predicate may be implemented entirely
6718
6679
  as ordinary Prolog and still be outside the cross-processor interoperability
@@ -6728,16 +6689,7 @@ follows Scryer's module name so explicit Scryer-style imports remain available.
6728
6689
  That interoperability profile currently spans 26 modules and is intentionally
6729
6690
  narrower than either implementation's union of exports; EyeProlog's explicit-state
6730
6691
  `random/3` and `uuid/3`, for example, remain useful extensions rather than shared
6731
- interfaces. Separately, all 32 bundled EyeProlog modules whose basenames overlap
6732
- Scryer's current `src/lib/` tree are checked against the frozen export snapshot in
6733
- `test/scryer-library-exports.json` and cover the corresponding Scryer public
6734
- predicate surface. The same structural check is now applied to Trealla: the 26
6735
- bundled modules that have public-module counterparts in Trealla `library/` cover
6736
- Trealla's exported predicates at pinned upstream commit
6737
- `f7a93bd521c07a4841f5123348111dd005918c89`, recorded in
6738
- `test/trealla-library-exports.json`. This is module-overlap coverage, not a claim
6739
- that EyeProlog bundles Trealla's native host libraries such as `curl`, `gsl`,
6740
- `janus`, `raylib`, `socket`, or `sqlite3`.
6692
+ interfaces. Separately, all 32 bundled EyeProlog modules whose basenames overlap Scryer's current `src/lib/` tree cover the corresponding Scryer public predicate surface. The 26 bundled modules that have public-module counterparts in Trealla `library/` cover Trealla's exported predicates at pinned upstream commit `f7a93bd521c07a4841f5123348111dd005918c89`. This is module-overlap coverage, not a claim that EyeProlog bundles Trealla's native host libraries such as `curl`, `gsl`, `janus`, `raylib`, `socket`, or `sqlite3`.
6741
6693
 
6742
6694
  Source reuse is preferred over translation. `clpb.pl`, `ordsets.pl`,
6743
6695
  `reif.pl`, and `ugraphs.pl` retain the upstream Prolog algorithms and license
@@ -6760,7 +6712,7 @@ parallel scheduling behavior. The
6760
6712
  [portable library overlap example](https://github.com/eyereasoner/eyeprolog/blob/main/examples/portable-library-overlap.pl)
6761
6713
  composes Boolean constraints, ordered sets, graphs, reification, delayed goals,
6762
6714
  generated names, character conversion, transposition, and explicit table
6763
- syntax in one checked program.
6715
+ syntax in one runnable program.
6764
6716
 
6765
6717
  Two matching upstream basenames are intentionally not exposed as portable
6766
6718
  libraries. The two `builtins.pl` files are private engine facades and have no
@@ -6853,12 +6805,7 @@ too few parameters raises `existence_error(lambda_parameter, ...)`. EyeProlog
6853
6805
  uses its ISO `copy_term/2` implementation for the fresh-copy step and does not
6854
6806
  require a separate `copy_term_nat/2` predicate.
6855
6807
 
6856
- Autoloading is a convenience layered on top of the module system and is
6857
- independent of the smaller interoperability profile. At build time EyeProlog
6858
- uses a generated index derived from every bundled `src/lib/*.pl` `module/2`
6859
- export list. An otherwise unresolved predicate in source, initialization code, an explicit
6860
- CLI/API goal, or an interactive top-level query therefore autoloads its canonical
6861
- bundled provider.
6808
+ Autoloading is a convenience layered on top of the module system and is independent of the smaller interoperability profile. An otherwise unresolved predicate in source, initialization code, an explicit CLI/API goal, or an interactive top-level query autoloads its canonical bundled provider.
6862
6809
  For example:
6863
6810
 
6864
6811
  - **`member/2`** — `library(lists)`
@@ -6871,9 +6818,7 @@ The resolution order is deliberately conservative with respect to Prolog
6871
6818
  semantics: a predicate already defined by the program wins; ISO/standard
6872
6819
  built-ins are not replaced by an autoloaded library; an explicit module import
6873
6820
  wins over autoloading; only then is the bundled autoload index consulted.
6874
- Facade modules such as `library(prologue)` may re-export predicates from focused
6875
- modules; the generated index chooses the unique module that actually defines
6876
- the predicate. If more than one bundled module genuinely defines the same
6821
+ Facade modules such as `library(prologue)` may re-export predicates from focused modules; autoload resolution chooses the unique module that actually defines the predicate. If more than one bundled module genuinely defines the same
6877
6822
  export, EyeProlog reports an import ambiguity and requires explicit
6878
6823
  `use_module/1-2` rather than guessing. The interactive top level applies this
6879
6824
  same resolution after a query has been parsed. Autoloading therefore supplies
@@ -6881,11 +6826,7 @@ predicates, not retroactive syntax: a library that introduces operators (for
6881
6826
  example `library(clpz)` and `ins`) must still be explicitly imported before a
6882
6827
  query or source term uses those operators.
6883
6828
 
6884
- The index is generated by `npm run generate:autoload` into
6885
- `src/library-autoload-index.js`, and the documentation regression suite checks
6886
- that it is synchronized with the current `src/lib/` sources. Explicit imports
6887
- remain the clearest way to state dependencies when portability or module intent
6888
- should be visible in the source:
6829
+ Explicit imports remain the clearest way to state dependencies when portability or module intent should be visible in the source:
6889
6830
 
6890
6831
  ```text
6891
6832
  :- use_module(library(lists)).
@@ -6897,22 +6838,11 @@ library dependency should be explicit. `--iso-strict` always disables EyeProlog
6897
6838
  library autoloading, so strict ISO execution never gains procedures from this
6898
6839
  implementation convenience.
6899
6840
 
6900
- `-w` / `--warnings` reports explicit dependencies on non-profile libraries and
6901
- calls to non-profile predicates from otherwise common modules. `--portable`
6902
- turns those diagnostics into a failing run, making the conservative profile
6903
- suitable for continuous integration. `npm run test:interop` executes the same
6904
- portable Towers of Hanoi source under EyeProlog, Trealla, and Scryer when those commands
6905
- are installed. Because those are external runtimes, the default `npm test`
6906
- instead validates all four generated OpenRuleBench source trees and their
6907
- engine-specific tabling and WFS adaptations without requiring them. The fast
6908
- structural check is also available directly as `npm run test:openrulebench`.
6841
+ `-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 `npm run test:interop` when EyeProlog, Trealla, and Scryer are installed.
6909
6842
 
6910
6843
  ### Specialized library implementation notes
6911
6844
 
6912
- The catalog and role summaries above define the public surface. The following
6913
- notes record implementation details and semantic boundaries that matter when a
6914
- library uses attributed variables, delayed goals, host services, tabling, or
6915
- mutable runtime state.
6845
+ Several libraries have implementation details and semantic boundaries that matter when they use attributed variables, delayed goals, host services, tabling, or mutable runtime state.
6916
6846
 
6917
6847
  `freeze(?Term,:Goal)` runs `Goal` immediately when `Term` is already nonvariable;
6918
6848
  otherwise it delays the goal until `Term` becomes nonvariable. Suspensions are
@@ -6942,9 +6872,7 @@ bindings make one aligned subterm pair sufficient. For example:
6942
6872
  ; A = B, dif(X, Y).
6943
6873
  ```
6944
6874
 
6945
- The catalog above is authoritative for the complete EyeProlog library surface.
6946
- The following notes describe useful parts of that surface without extending the
6947
- cross-engine claims made above.
6875
+ The following notes describe implementation-specific library behavior without extending the cross-engine compatibility claims.
6948
6876
 
6949
6877
  `library(atts)` is the Prolog-facing attributed-variable layer over the persistent
6950
6878
  annotated-variable machinery in `src/term.js`, with its small host bridge in
@@ -6953,9 +6881,7 @@ accepts `:- attribute ...` declarations, invokes module-local
6953
6881
  `verify_attributes/3` before an attributed binding is committed, and schedules
6954
6882
  the returned goals immediately after the binding. Attribute maps are copied only
6955
6883
  when changed and therefore backtrack with `Env` branches; the interactive top
6956
- level projects module `attribute_goals//1` hooks as residual goals. The checked
6957
- [`examples/attributed-variables.pl`](https://github.com/eyereasoner/eyeprolog/blob/main/examples/attributed-variables.pl)
6958
- demonstrates binding verification and attribute transfer across aliases.
6884
+ level projects module `attribute_goals//1` hooks as residual goals. [`examples/attributed-variables.pl`](https://github.com/eyereasoner/eyeprolog/blob/main/examples/attributed-variables.pl) demonstrates binding verification and attribute transfer across aliases.
6959
6885
 
6960
6886
  `library(clpz)` is Markus Triska's MIT-licensed Scryer Prolog implementation of
6961
6887
  constraint logic programming over integers, bundled as `src/lib/clpz.pl`.
@@ -7023,15 +6949,13 @@ the common stateful generator used by `uuidv4/1`.
7023
6949
  <!-- eyeprolog-predicate-reference:start -->
7024
6950
  ### Complete predicate indicator reference
7025
6951
 
7026
- This generated reference covers all **518 distinct predicate indicators** in the normal EyeProlog surface: 129 core registry indicators plus 391 bundled-library indicators, with `phrase/2` and `phrase/3` present in both layers and therefore counted once.
6952
+ The normal EyeProlog surface contains **518 distinct predicate indicators**: 129 core registry indicators plus 391 bundled-library indicators, with `phrase/2` and `phrase/3` present in both layers and therefore counted once.
7027
6953
 
7028
6954
  Each entry is a compact contract. `+` marks a principal input, `-` a principal output, and `?` an argument that may be supplied or produced. These are documented operating modes rather than parser-enforced mode declarations. **Solutions** uses `det`, `semidet`, `multi`, `nondet`, `delayed`, `meta`, `mode-dependent`, `declaration`, or `terminal`; `meta` means the solution behavior depends materially on a called goal.
7029
6955
 
7030
- The reference uses stacked entries instead of wide Markdown tables, so principal calls and contracts wrap naturally on narrow screens without horizontal scrolling. It is checked against the live core registry and every `src/lib/*.pl` export. Adding, removing, or renaming a predicate therefore makes the documentation test fail until its contract metadata is updated.
7031
-
7032
6956
  #### Predicate index
7033
6957
 
7034
- Every indicator below links directly to its own explicit anchor. These anchors are generated as stable numeric IDs instead of relying on Markdown heading-slug rules, so the links behave consistently in GitHub Pages and other renderers.
6958
+ Each indicator links directly to its contract.
7035
6959
 
7036
6960
  **Symbols:** [`-->/2`](#predicate-reference-0001) · [`->/2`](#predicate-reference-0002) · [`,/3`](#predicate-reference-0003) · [`;/2`](#predicate-reference-0004) · [`;/3`](#predicate-reference-0005) · [`!/0`](#predicate-reference-0006) · [`.../2`](#predicate-reference-0007) · [`@</2`](#predicate-reference-0008) · [`@=</2`](#predicate-reference-0009) · [`@>/2`](#predicate-reference-0010) · [`@>=/2`](#predicate-reference-0011) · [`*/1`](#predicate-reference-0012) · [`\/1`](#predicate-reference-0013) · [`\/2`](#predicate-reference-0014) · [`\/3`](#predicate-reference-0015) · [`\/4`](#predicate-reference-0016) · [`\/5`](#predicate-reference-0017) · [`\/6`](#predicate-reference-0018) · [`\/7`](#predicate-reference-0019) · [`\/8`](#predicate-reference-0020) · [`\+/1`](#predicate-reference-0021) · [`\=/2`](#predicate-reference-0022) · [`\==/2`](#predicate-reference-0023) · [`#/\/2`](#predicate-reference-0024) · [`#\//2`](#predicate-reference-0025) · [`#\/1`](#predicate-reference-0026) · [`#\/2`](#predicate-reference-0027) · [`#\=/2`](#predicate-reference-0028) · [`#</2`](#predicate-reference-0029) · [`#</3`](#predicate-reference-0030) · [`#<==/2`](#predicate-reference-0031) · [`#<==>/2`](#predicate-reference-0032) · [`#=/2`](#predicate-reference-0033) · [`#=/3`](#predicate-reference-0034) · [`#=</2`](#predicate-reference-0035) · [`#==>/2`](#predicate-reference-0036) · [`#>/2`](#predicate-reference-0037) · [`#>=/2`](#predicate-reference-0038) · [`^/10`](#predicate-reference-0039) · [`^/3`](#predicate-reference-0040) · [`^/4`](#predicate-reference-0041) · [`^/5`](#predicate-reference-0042) · [`^/6`](#predicate-reference-0043) · [`^/7`](#predicate-reference-0044) · [`^/8`](#predicate-reference-0045) · [`^/9`](#predicate-reference-0046) · [`+\/2`](#predicate-reference-0047) · [`+\/3`](#predicate-reference-0048) · [`+\/4`](#predicate-reference-0049) · [`+\/5`](#predicate-reference-0050) · [`+\/6`](#predicate-reference-0051) · [`+\/7`](#predicate-reference-0052) · [`+\/8`](#predicate-reference-0053) · [`+\/9`](#predicate-reference-0054) · [`</2`](#predicate-reference-0055) · [`=:=/2`](#predicate-reference-0056) · [`=../2`](#predicate-reference-0057) · [`=/2`](#predicate-reference-0058) · [`=/3`](#predicate-reference-0059) · [`=\=/2`](#predicate-reference-0060) · [`=</2`](#predicate-reference-0061) · [`==/2`](#predicate-reference-0062) · [`>/2`](#predicate-reference-0063) · [`>=/2`](#predicate-reference-0064) · [`$-/1`](#predicate-reference-0065) · [`$/1`](#predicate-reference-0066)
7037
6961
 
@@ -9605,13 +9529,7 @@ and the chosen resource measure improves on the relevant scale case.
9605
9529
 
9606
9530
  ### The corpus as executable documentation
9607
9531
 
9608
- The files under `examples/` pair readable programs with checked output under
9609
- `examples/output/`. The conformance cases under `test/conformance/` focus on
9610
- language behavior, including success, failure, errors, warnings, and file
9611
- loading. Use an example to learn a modeling pattern and a conformance case to
9612
- settle an exact processor question. `npm test` checks both along with the book's
9613
- extracted programs; `npm run generate` refreshes those extracted examples after
9614
- changing executable book blocks.
9532
+ The files under `examples/` pair readable programs with checked output under `examples/output/`. The conformance cases under `test/conformance/` focus on language behavior, including success, failure, errors, warnings, and file loading. Use an example to learn a modeling pattern and a conformance case to settle an exact processor question. Run `npm test` to execute the complete correctness corpus.
9615
9533
 
9616
9534
  **Checkpoint.** Run one example with `--proof --stats`. Identify which bytes
9617
9535
  belong to the reusable logical result, which describe this execution, and which
@@ -9700,16 +9618,10 @@ The [examples directory](https://github.com/eyereasoner/eyeprolog/tree/main/exam
9700
9618
  top-level directory contains **224 self-contained runnable programs**. Every
9701
9619
  source program has an exact answer file under
9702
9620
  [examples/output](https://github.com/eyereasoner/eyeprolog/tree/main/examples/output/), and **61 selected programs** have a checked
9703
- explanation under [examples/proof](https://github.com/eyereasoner/eyeprolog/tree/main/examples/proof/). The thematic tables below link every top-level program and open the program
9621
+ explanation under [examples/proof](https://github.com/eyereasoner/eyeprolog/tree/main/examples/proof/). The thematic lists link every top-level program and open the program
9704
9622
  itself rather than merely naming it.
9705
9623
 
9706
- The generated [`examples/book/`](https://github.com/eyereasoner/eyeprolog/tree/main/examples/book/) tree serves a different
9707
- purpose: it mirrors the complete inline EyeProlog displays chapter by chapter.
9708
- Those files are checked for syntax, and displays containing queries are
9709
- executed, but some teaching fragments deliberately depend on neighboring
9710
- facts or helpers. Use the top-level catalog below when you want a self-contained
9711
- program with a golden answer; use `examples/book/` when you want the exact
9712
- display being discussed on a page.
9624
+ [`examples/book/`](https://github.com/eyereasoner/eyeprolog/tree/main/examples/book/) mirrors the inline EyeProlog displays chapter by chapter. Those files are checked for syntax, and displays containing queries are executed, but some teaching fragments deliberately depend on neighboring facts or helpers. Use the top-level examples when you want a self-contained program with a golden answer; use `examples/book/` when you want the exact display being discussed on a page.
9713
9625
 
9714
9626
  For any named example, the three useful views are:
9715
9627
 
@@ -10161,11 +10073,7 @@ When adding an example:
10161
10073
  6. include both a positive case and a meaningful boundary or failure case;
10162
10074
  7. run the full corpus before treating the example as documentation.
10163
10075
 
10164
- The full set of runnable source programs is checked against exact output, and
10165
- the tables in this chapter link every top-level program under `examples/`. The
10166
- thematic tables remain the recommended reading routes; the final alphabetical
10167
- table completes the index. Apply the same reading discipline to every example—
10168
- sentence, mode, finite domain, answer, proof, and revision.
10076
+ Every top-level program under `examples/` appears in the thematic lists and the alphabetical index. Apply the same reading discipline to every example—sentence, mode, finite domain, answer, proof, and revision.
10169
10077
 
10170
10078
  ## 42. Standards, limits, and implementation boundaries
10171
10079
 
@@ -10184,8 +10092,6 @@ syntax. Separate corpora cover expected errors, warnings, and proofs:
10184
10092
  npm run test:conformance
10185
10093
  npm run test:iso-strict
10186
10094
  npm run test:wg17
10187
- # Refresh the vendored TU Wien WG17 inventory when upstream changes:
10188
- npm run wg17:upgrade
10189
10095
  node test/run-conformance-report.mjs
10190
10096
  ```
10191
10097
 
@@ -10209,32 +10115,19 @@ must preserve the same observable outcome. Additional normal-mode syntax may
10209
10115
  accept texts outside the strict grammar, but it may not reinterpret an accepted
10210
10116
  standard case.
10211
10117
 
10212
- The complete suite must pass before release. The file-based conformance corpus
10213
- contains 802 cases, including 386 focused ISO
10214
- cases derived from the success, failure, mode, and error behavior in
10215
- ISO/IEC 13211-1 clauses 7 and 8, Part 2 modules, and Part 3 grammar rules.
10216
- Separate exact-output suites check 210 normal
10217
- examples and 61 proof examples; all extracted book programs are parsed and
10218
- their declared goals are executed. The eight-case
10118
+ The file-based conformance corpus contains 802 cases, including 386 focused ISO cases derived from the success, failure, mode, and error behavior in ISO/IEC 13211-1 clauses 7 and 8, Part 2 modules, and Part 3 grammar rules.
10119
+ Separate exact-output suites check 210 normal examples and 61 proof examples; all executable chapter programs are parsed and their declared goals are executed. The eight-case
10219
10120
  playground contract suite imports the production worker, sends real reasoning
10220
10121
  requests through its message protocol, and crawls the served module graph for
10221
- missing assets, bad MIME types, and static Node-only imports. The generated
10222
- `conformance-report.md` is the authoritative source for the current executable
10223
- WG17 syntax result and file-based conformance category totals.
10122
+ missing assets, bad MIME types, and static Node-only imports. `conformance-report.md` records the current executable WG17 syntax result and file-based conformance category totals.
10224
10123
 
10225
- ### Generated and checked repository material
10124
+ ### Conformance artifacts
10226
10125
 
10227
- Repository artifacts have distinct roles:
10126
+ The repository exposes several forms of executable evidence:
10228
10127
 
10229
- - `conformance-report.md` executes the vendored WG17 syntax gate and also inventories the file-based conformance corpus;
10230
- - `examples/book/` is extracted from executable code blocks in this book and
10231
- should be rebuilt with `npm run generate` rather than edited directly;
10232
- - `examples/output/` and `examples/proof/` contain reviewed exact-output
10233
- goldens that make behavior changes visible in version control.
10234
-
10235
- Release preparation runs the complete suite and refreshes the conformance
10236
- report. Keeping these details here allows the README to remain a short project
10237
- landing page while this book remains the implementation reference.
10128
+ - `conformance-report.md` records the vendored WG17 syntax result and inventories the file-based conformance corpus;
10129
+ - `examples/book/` contains the executable code displays associated with the chapters;
10130
+ - `examples/output/` and `examples/proof/` contain reviewed exact-output goldens that make behavior changes visible in version control.
10238
10131
 
10239
10132
  Run the browser contract independently with:
10240
10133
 
@@ -10266,13 +10159,10 @@ that Part 1 strict surface.
10266
10159
  The strict-core audit has explicit dispositions for the Clause 5 processor
10267
10160
  obligations, Clause 6 syntax and rejection families, Clause 7 term/execution/I/O
10268
10161
  and error semantics, the 8.2-8.17 built-in families, and Clause 9 evaluable
10269
- functors. The complete vendored WG17 syntax matrix is a release gate, and each
10270
- strict-success WG17 observation is also checked through normal mode so syntax
10271
- extensions cannot reinterpret accepted standard text. Implementation-defined
10162
+ functors. The complete vendored WG17 syntax matrix is checked together with normal-mode safety: each strict-success WG17 observation must keep the same result when normal-mode extensions are enabled. Implementation-defined
10272
10163
  choices—including the Unicode-scalar processor character set, stream details,
10273
10164
  flag defaults, floating behavior, and signed bitwise/shift semantics—are indexed
10274
- in `test/conformance/ISO-IMPLEMENTATION-DEFINED.md`. The release-facing closure
10275
- ledger is `test/conformance/ISO-COMPLIANCE.md`.
10165
+ in `test/conformance/ISO-IMPLEMENTATION-DEFINED.md`. The conformance closure ledger is `test/conformance/ISO-COMPLIANCE.md`.
10276
10166
 
10277
10167
  Notable implementation boundaries are:
10278
10168
 
@@ -10294,9 +10184,7 @@ Notable implementation boundaries are:
10294
10184
 
10295
10185
  Write terms explicitly, keep variables uppercase or underscore-prefixed, and
10296
10186
  quote atom names that are neither lowercase plain names nor graphic tokens.
10297
- The conformance ledger and release gates verify this documented strict-core
10298
- boundary. Their closure is implementation evidence, not independent ISO
10299
- certification.
10187
+ The conformance ledger provides executable evidence for this documented strict-core boundary; it is not independent ISO certification.
10300
10188
 
10301
10189
  ### Security and resource use
10302
10190
 
@@ -10451,8 +10339,7 @@ can discuss, answers you can test, and proofs you can carry forward as data.
10451
10339
 
10452
10340
  ### Glossary
10453
10341
 
10454
- This glossary fixes the book's vocabulary. Definitions describe EyeProlog unless a
10455
- broader mathematical meaning is explicitly stated.
10342
+ The glossary uses the following EyeProlog-specific meanings unless a broader mathematical meaning is explicitly stated.
10456
10343
 
10457
10344
  **Aggregate.** A relation that evaluates a finite nested solution space and
10458
10345
  combines its solutions, as `findall/3`, `countall/2`, `sumall/3`,
@@ -10677,9 +10564,7 @@ such as a path, assignment, factorization, schedule, or proof-relevant object.
10677
10564
 
10678
10565
  ## 44. Twelve laboratories
10679
10566
 
10680
- These laboratories turn the book into a course. Each has a deliverable, an
10681
- acceptance test, and a reflection question. Complete them in order or choose a
10682
- route suited to a study group.
10567
+ These laboratories turn the preceding material into hands-on work. Each has a deliverable, an acceptance test, and a reflection question. Complete them in order or choose a route suited to a study group.
10683
10568
 
10684
10569
  <figure>
10685
10570
  <img src="book-assets/laboratory-progression.svg" alt="Twelve laboratories progress from relational foundations through finite search, mathematical and symbolic methods, domain reasoning, and a release-quality reasoning service.">
@@ -11061,18 +10946,5 @@ counterexample refutes a universal claim; an exhausted finite carrier proves a
11061
10946
  property only for that model; repeated bounded confirmations do not become an
11062
10947
  unbounded theorem.
11063
10948
 
11064
- For laboratory checkpoints, leave an artifact. A useful completion is not
11065
- merely a paragraph: it is a small source file, predicted output, actual output,
11066
- and one sentence explaining any difference. The extracted chapter examples,
11067
- top-level goldens, and `npm test` demonstrate that rhythm at repository scale.
11068
-
11069
- # Part XII — Development note
11070
-
11071
- ## 46. AI-assisted editing
11072
-
11073
- GPT-5.6 was used during the development of this book to assist with chapter
11074
- reorganisation, refinement of explanations, and review of examples and
11075
- diagrams.
10949
+ For laboratory checkpoints, leave an artifact. A useful completion is not merely a paragraph: it is a small source file, predicted output, actual output, and one sentence explaining any difference.
11076
10950
 
11077
- All suggestions were evaluated and directed by the author, who remains
11078
- responsible for the book's claims, choices, and any remaining errors.
@@ -147,19 +147,16 @@ function renderSection(byIndicator, surface) {
147
147
  START,
148
148
  '### Complete predicate indicator reference',
149
149
  '',
150
- `This generated reference covers all **${EXPECTED_COUNT} distinct predicate indicators** in the normal EyeProlog surface: ` +
150
+ `The normal EyeProlog surface contains **${EXPECTED_COUNT} distinct predicate indicators**: ` +
151
151
  `${surface.core.size} core registry indicators plus ${surface.library.size} bundled-library indicators, with ` +
152
152
  '`phrase/2` and `phrase/3` present in both layers and therefore counted once.',
153
153
  '',
154
154
  'Each entry is a compact contract. `+` marks a principal input, `-` a principal output, and `?` an argument that may be supplied or produced. ' +
155
155
  'These are documented operating modes rather than parser-enforced mode declarations. **Solutions** uses `det`, `semidet`, `multi`, `nondet`, `delayed`, `meta`, `mode-dependent`, `declaration`, or `terminal`; `meta` means the solution behavior depends materially on a called goal.',
156
156
  '',
157
- 'The reference uses stacked entries instead of wide Markdown tables, so principal calls and contracts wrap naturally on narrow screens without horizontal scrolling. ' +
158
- 'It is checked against the live core registry and every `src/lib/*.pl` export. Adding, removing, or renaming a predicate therefore makes the documentation test fail until its contract metadata is updated.',
159
- '',
160
157
  '#### Predicate index',
161
158
  '',
162
- 'Every indicator below links directly to its own explicit anchor. These anchors are generated as stable numeric IDs instead of relying on Markdown heading-slug rules, so the links behave consistently in GitHub Pages and other renderers.',
159
+ 'Each indicator links directly to its contract.',
163
160
  '',
164
161
  ];
165
162