eyeprolog 1.3.61 → 1.3.63

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
@@ -212,15 +212,14 @@ unchanged.
212
212
 
213
213
  This README intentionally stays at the project-overview level. The detailed
214
214
  implementation reference is [*The Art of EyeProlog*](the-art-of-eyeprolog.md).
215
- The current Part 1 audit status and remaining release conditions are recorded in
215
+ The current Part 1 audit status and closure criteria are recorded in
216
216
  [`test/conformance/ISO-COMPLIANCE.md`](test/conformance/ISO-COMPLIANCE.md);
217
217
  implementation-defined decisions are indexed in
218
218
  [`ISO-IMPLEMENTATION-DEFINED.md`](test/conformance/ISO-IMPLEMENTATION-DEFINED.md). The complete
219
219
  vendored WG17 syntax corpus and the strict ISO regression suite run as release
220
220
  gates.
221
221
 
222
- EyeProlog does not claim independent ISO certification while the explicit exit
223
- checklist still contains unresolved normative or unexplained-deviation items.
222
+ The release-facing Part 1 audit ledger has explicit dispositions for its tracked requirements. This implementation evidence is not an independent ISO certification.
224
223
 
225
224
  ## Module and definite clause grammar compatibility profiles
226
225
 
@@ -285,7 +284,7 @@ headroom, so an exhausted finite heap is reported as a catchable
285
284
  `library(iso_ext)` is also accepted as a common interop module name.
286
285
  EyeProlog exports `call_nth/2`, `time/1`, and the DCG helper `... //0` there.
287
286
  The latter describes an arbitrary number of input elements and supports the
288
- nonterminal hand-off benchmark discussed in issue #49. These common predicates
287
+ nonterminal hand-off benchmark used by the interoperability tests. These common predicates
289
288
  may be imported explicitly, while source/CLI/API dependency loading can resolve
290
289
  their unqualified forms conservatively. For Trealla-style interactive timing,
291
290
  `time/1` is also available directly in the normal EyeProlog runtime; strict ISO
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "1.3.61",
6
+ "version": "1.3.63",
7
7
  "description": "EyeProlog turns facts and rules into answers and proofs.",
8
8
  "type": "module",
9
9
  "main": "./index.js",
@@ -209,7 +209,7 @@ The Corrigendum 2 additions have the same shape.
209
209
  | 8.11.5 errors: argument shapes | non-atom mode; non-list options; non-variable stream output (Cor.2 uninstantiation) | covered | strict `open/4` assertions |
210
210
  | 8.11.5 errors: domains | invalid source/sink, I/O mode, or stream option | covered | strict `open/4` assertions |
211
211
  | 8.11.5 source/sink errors | missing read source or source/sink that cannot be opened | covered | strict host-I/O probes for existence/permission conditions |
212
- | 8.11.5 alias collision | `alias(A)` already names an open stream -> open permission error with complete `alias(A)` culprit | covered | focused issue #65 alias-collision regression |
212
+ | 8.11.5 alias collision | `alias(A)` already names an open stream -> open permission error with complete `alias(A)` culprit | covered | focused alias-collision regression |
213
213
  | 8.11.5 `reposition(true)` impossible | permission error when the requested stream cannot be repositioned | covered | stream option corpus and implementation-defined stream capability checks |
214
214
  | 8.11.6 `close/2`, `close/1` | close an open non-standard stream and maintain current-stream fallbacks | covered | stream lifecycle corpus |
215
215
  | 8.11.6 errors | variable stream/option element; non-list options; invalid stream-or-alias; invalid close option; missing stream | covered | strict close assertions |
@@ -364,7 +364,7 @@ built-in matrix does not have a gap at 8.17.
364
364
  | 8.17.4 variable status | instantiation error | covered | strict `halt(X)` |
365
365
  | 8.17.4 non-integer status | integer type error | covered | strict `halt(a)` |
366
366
 
367
- ## Remaining audit work
367
+ ## Closure note
368
368
 
369
369
  The built-in **8.2-8.17 row audit is complete** at the level tracked by this
370
370
  file: prescribed modes, success/failure behavior, individual error conditions,
@@ -372,9 +372,6 @@ and conditional/not-applicable processor branches all have explicit outcomes.
372
372
  ISO 7.12 simultaneous-error selection remains an implementation-dependent
373
373
  processor choice unless more specific normative text constrains it.
374
374
 
375
- The remaining #65 work is therefore above/below this built-in table. The
376
- 7.1-7.3 term-semantics and 7.9/Clause 9 evaluable-functor rows are now closed in
377
- their dedicated matrices. What remains is Clause 6 text/rejection mapping,
378
- Clause 7.4-7.8 plus higher-level 7.10/7.12 processor/control semantics, residual
379
- Clause 5 dependency rows and the unexplained-deviation exit criterion
380
- recorded in `ISO-COMPLIANCE.md`.
375
+ The surrounding Clause 5-7 processor requirements are closed in
376
+ `ISO-PROCESSOR-REQUIREMENTS.md` and `ISO-COMPLIANCE.md`; this matrix remains the
377
+ detailed evidence for the 8.2-8.17 built-in layer.
@@ -19,39 +19,38 @@ relevant implementation-dependent overlap choice to an explicit audit outcome.
19
19
 
20
20
  | Requirement | Status | EyeProlog evidence / remaining work |
21
21
  | --- | --- | --- |
22
- | 5.1(a) prepare conforming Prolog text | audit | Clause 6 parser/tokenizer coverage, directive coverage, syntax-error corpus, and the [complete vendored WG17 syntax matrix](WG17-SYNTAX-STATUS.md). Wider shall-by-shall text-processing audit remains open. |
23
- | 5.1(b) execute conforming Prolog goals | audit | Clause 7-9 conformance corpus plus regression/API/example gates. The 7.1-7.8 term/preparation/database/control rows, 7.9/Clause 9 arithmetic, and 8.2-8.17 built-in row audits are now closed; the dependency remains open on higher-level 7.10 and residual processor-level 7.12 semantics. |
24
- | 5.1(c) reject nonconforming text/read-terms | audit | Dedicated syntax-error cases and strict-core extension rejection. Exhaustive lexical rejection coverage remains open. |
25
- | 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. Rows marked `audit gap` remain conformance work, but the variation is no longer undocumented. |
22
+ | 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 366-case vendored WG17 syntax matrix; 7.4 preparation/directive behavior is separately closed. |
23
+ | 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. |
24
+ | 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. |
25
+ | 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 `audit gap` category for future discoveries; no current release-facing row depends on one. |
26
26
  | 5.1(e) offer a strictly conforming mode | covered | `--iso-strict` and API option `isoStrict: true` restrict the processor to the Part 1 + Corrigenda 1-3 core language surface, remove EyeProlog-only registry/flag/operator features, disable automatic tabling/recursion guards, and reject the normal-profile host `stringTerm/1` term type at strict program/goal entry. |
27
- | 5.4 accompanying documentation | covered | *The Art of EyeProlog* remains the implementation reference; [ISO-IMPLEMENTATION-DEFINED.md](ISO-IMPLEMENTATION-DEFINED.md) is the closed clause-by-clause 5.4 decision index and points each decision to implementation evidence or an explicit audit gap. |
28
- | 5.5 extension boundaries | audit | [ISO-PROCESSOR-REQUIREMENTS.md](ISO-PROCESSOR-REQUIREMENTS.md) splits 5.5 into its individual extension hooks. Operators, character conversion, the normal-profile host string type, directives, control constructs, flags, built-ins, evaluable functors, and reserved atoms now have explicit decisions. The remaining open extension work is now concentrated in exhaustive syntax-preservation (5.5.1); the Prolog-visible additional-side-effect boundary (5.5.6) is explicitly filtered in strict mode and host instrumentation is documented as an embedding concern. |
27
+ | 5.4 accompanying documentation | covered | *The Art of EyeProlog* remains the implementation reference; [ISO-IMPLEMENTATION-DEFINED.md](ISO-IMPLEMENTATION-DEFINED.md) is the closed clause-by-clause 5.4 decision index and points each decision to implementation evidence. |
28
+ | 5.5 extension boundaries | covered | [ISO-PROCESSOR-REQUIREMENTS.md](ISO-PROCESSOR-REQUIREMENTS.md) gives an explicit disposition for every 5.5 extension hook. The Clause 6 cross-profile gate verifies that normal-mode syntax extensions do not reinterpret standard text accepted by the strict reader. |
29
29
 
30
30
  ## Normative language families
31
31
 
32
32
  | Standard area | Status | Current evidence |
33
33
  | --- | --- | --- |
34
- | Clause 6 — tokens, terms, lists, operators, quoted text | audit | Complete vendored WG17 syntax matrix, `lexical_and_curly_terms`, `scryer_lexical_terms`, operator suites, syntax-error cases, quoted-layout/escape error cases, writer/read-back regressions, and Unicode-scalar PCS/collation boundary tests. A cross-profile gate now verifies that every WG17 case accepted by the strict Part 1 reader has the same observable outcome under normal-mode syntax extensions. The implementation-defined 6.5/6.6 character-model decisions are closed; the remaining work is the explicit production-by-production shall map. |
34
+ | 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 366-case WG17 syntax matrix provides independent production-level coverage, 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. |
35
35
  | 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. |
36
36
  | 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. |
37
37
  | 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. |
38
38
  | 7.7 — execution and backtracking | covered | [ISO-PROLOG-TEXT-EXECUTION-MATRIX.md](ISO-PROLOG-TEXT-EXECUTION-MATRIX.md) closes ordinary clause selection/backtracking, source/database order, empty-versus-unknown procedures, logical-update visibility, and strict dispatch. EyeProlog automatic tabling, cycle guards, and recursive numeric shortcuts remain disabled in the strict profile. |
39
39
  | 7.8 — control constructs and exceptions | covered | [ISO-PROLOG-TEXT-EXECUTION-MATRIX.md](ISO-PROLOG-TEXT-EXECUTION-MATRIX.md) closes `true/0`, `fail/0`, `call/1`, cut, conjunction, disjunction, if-then(-else), and `catch/3`/`throw/1`, including Corrigendum 2 catchability of errors arising from the protected goal and Corrigendum 3 term-to-body conversion. The 8.15 built-in additions remain independently row-audited. |
40
40
  | 7.9 — expression evaluation | covered | [ISO-EVALUABLE-FUNCTOR-MATRIX.md](ISO-EVALUABLE-FUNCTOR-MATRIX.md) closes recursive evaluation, direct-variable precedence, corrected non-evaluable `F/N` errors (including STC #69), operand template/type rules, mixed arithmetic-comparison conversion, exceptional values, and finite-host resource normalization. The audit also fixes float-only `float_integer_part/1` and `float_fractional_part/1` so even huge valid integers reach `type_error(float,...)` before any I->F overflow. |
41
- | 7.10 — input/output concepts | audit | Stream, character/byte I/O, read/write options, operator-sensitive write-back, and Corrigendum 3 writer cases. The complete 8.11-8.14 built-in mode/error family is now row-audited in [ISO-BUILTIN-MODE-ERROR-MATRIX.md](ISO-BUILTIN-MODE-ERROR-MATRIX.md), including lifecycle/current-stream handling, stream positions, text/binary permissions, EOF actions, `force(true)`, input-code representation timing, term-I/O options, operators, and character conversion. `stream_property/2` now also distinguishes a malformed stream-term (domain error) from a valid stream-term whose stream is no longer open (ordinary failure). The higher-level 7.10 source/sink, buffering, positioning, and implementation-defined stream semantics remain under shall-by-shall audit. |
41
+ | 7.10 — input/output concepts | covered | Higher-level stream semantics are pinned for non-atom ground stream terms, alias lifetime, current/target stream selection and fallback, write truncation, append positioning, contradictory stream options, exact binary round-tripping, flushing, standard-stream close behavior, and repositioned overwrite. The complete 8.11-8.14 built-in mode/error family remains row-audited in [ISO-BUILTIN-MODE-ERROR-MATRIX.md](ISO-BUILTIN-MODE-ERROR-MATRIX.md), while all implementation-defined stream choices are indexed in [ISO-IMPLEMENTATION-DEFINED.md](ISO-IMPLEMENTATION-DEFINED.md). |
42
42
  | 7.11 — flags | covered | The complete Part 1 flag set, selected defaults, standard value domains, changeability, `current_prolog_flag/2`, and `set_prolog_flag/2` error behavior have dedicated strict tests. EyeProlog selects `bounded=false` and `integer_rounding_function=toward_zero`; valid alternative values of those fixed flags reach `permission_error(modify,flag,...)`, while `max_integer` and `min_integer` have no current value. STC #70 is recorded explicitly: EyeProlog has no separate finite procedure-arity ceiling, so the optional `max_procedure_arity` flag is absent while `max_arity` remains `unbounded`. Strict mode excludes the EyeProlog `occurs_check` extension. |
43
- | 7.12 — errors | audit | ISO `error(Error, Context)` envelope, type/domain/permission/representation/evaluation/syntax/resource families and focused error cases. [ISO-BUILTIN-MODE-ERROR-MATRIX.md](ISO-BUILTIN-MODE-ERROR-MATRIX.md) now gives explicit mode/error-condition outcomes across the complete 8.2-8.17 built-in family, including Corrigendum additions and not-applicable conditional branches. The audit records the 7.12 rule that simultaneous error conditions are implementation dependent: overlap regressions document stable EyeProlog choices rather than inventing a universal table-order requirement. Remaining work is concentrated in higher-level 7.10 stream semantics and residual processor-level error conditions. |
43
+ | 7.12 — errors | covered | The strict error-envelope gate exercises instantiation, type, domain, existence, permission, representation, evaluation, resource, syntax, and system errors through `error(Error, Context)`. Built-in rows provide the individual prescribed conditions, implementation-defined representation/context choices are documented, and simultaneous-error regressions pin deterministic EyeProlog choices without treating textual table order as normative. |
44
44
  | 8.2-8.17 — built-in predicates | covered | [ISO-BUILTIN-MODE-ERROR-MATRIX.md](ISO-BUILTIN-MODE-ERROR-MATRIX.md) now records the complete Part 1 + Corrigenda built-in family at one row per prescribed mode, success/failure behavior, individual error condition, and conditional/not-applicable branch. The row audit exposed and fixed source/runtime 7.6.2 body conversion/variable sharing, strict host-string leakage, input-code error timing, `close/2` force handling, and closed-stream `stream_property/2` behavior. Simultaneous-error choices are documented as implementation dependent under 7.12 unless separately constrained. |
45
45
  | Clause 9 — evaluable functors | covered | [ISO-EVALUABLE-FUNCTOR-MATRIX.md](ISO-EVALUABLE-FUNCTOR-MATRIX.md) records the published Part 1 + Corrigenda arithmetic templates and exceptional branches across 9.1, 9.3, and 9.4. It pins the unbounded integer model, `rndI`/`rndF`/`resultF` choices, float-only conversion rules, I->F overflow, explicit `exp/1` and power underflow, Corrigendum 2 additions and mixed-type `max/2`/`min/2` implementation-dependent choice, Corrigendum 3 negative-power correction, signed bitwise/shift choices, and resource-error translation. Post-N289 STC #75 remains a separately tracked draft proposal rather than a silent change to the published baseline. |
46
46
  | Corrigendum 1 | covered | Double-quoted atom/operator-priority corrections have dedicated cases. |
47
47
  | Corrigendum 2 | covered | Added predicates/functors, catch corrections, bar/operator and uninstantiation corrections have dedicated cases. |
48
48
  | Corrigendum 3 | covered | Writer options, `variable_names/1`, canonical list output and negative-power corrections have dedicated cases. |
49
49
 
50
- ## Issue #65 conformance corrections
50
+ ## Conformance corrections and audit closure
51
51
 
52
- The issue #65 audit against the licensed Part 1 text and Corrigenda closed two
53
- concrete mismatches without changing the remaining audit rows into blanket
54
- conformance claims:
52
+ The audit against the licensed Part 1 text and Corrigenda closed two
53
+ concrete mismatches that are now part of the closed Part 1 audit:
55
54
 
56
55
  - `bounded=false` no longer exposes implementation-specific `unbounded` values
57
56
  for `max_integer` or `min_integer`; the corresponding
@@ -61,7 +60,7 @@ conformance claims:
61
60
  and feeds the same mapping into execution-time term input.
62
61
 
63
62
  A follow-on audit made the processor-character-set/collation choices explicit.
64
- Issue #67 then corrected an over-strict interpretation: because PCS membership
63
+ A follow-up processor-character-set review corrected an over-strict interpretation: because PCS membership
65
64
  and extended-character classification are implementation defined by Part 1,
66
65
  `--iso-strict` must not replace EyeProlog's ordinary processor choice. Both
67
66
  profiles now use Unicode scalar values as PCS members and collating integers;
@@ -73,7 +72,7 @@ WG17 syntax matrix remains a release gate.
73
72
 
74
73
 
75
74
  The subsequent arity audit originally selected a finite `max_arity=65535`, but
76
- issue #66 and the post-Corrigendum STC review exposed that as the wrong
75
+ the post-Corrigendum STC arity review exposed that as the wrong
77
76
  abstraction: Part 1 `max_arity` is the maximum arity of **compound terms**, not
78
77
  a procedure-arity limit. EyeProlog now again selects `max_arity=unbounded` and
79
78
  removes the artificial 65535 checks from source parsing, `functor/3`, `=../2`,
@@ -88,7 +87,7 @@ The public WG17 `number_chars/2` comparison used in preparation of Corrigendum
88
87
  2 has additionally been checked during the audit. It remains supporting review
89
88
  evidence rather than a duplicated vendored corpus or release criterion.
90
89
 
91
- A further issue #65 audit closes the Part 1 flag family and tightens the 8.14
90
+ The flag and term-I/O audit closes the Part 1 flag family and tightens the 8.14
92
91
  term-I/O/operator error rules. The strict flag registry now distinguishes a
93
92
  standard value that is valid but not selectable from a value outside the
94
93
  standard domain: attempts to change fixed `bounded` or
@@ -102,7 +101,7 @@ the Part 1 plus Corrigendum 3 option surface; the normal-profile
102
101
  extension.
103
102
 
104
103
 
105
- The current continuation of issue #65 expands that audit into Prolog-text,
104
+ The preparation, stream, conversion, sorting, and arithmetic audit expands the coverage into Prolog-text,
106
105
  stream, atomic-conversion, sorting, and arithmetic edge cases. Strict
107
106
  preparation now enforces the Part 1 declaration constraints for `dynamic/1`,
108
107
  `multifile/1`, and `discontiguous/1`, including cross-text multifile use and
@@ -112,13 +111,11 @@ requirements, and tightens creation, truncation/append, repositioning, flush,
112
111
  EOF, close, and current-stream behavior. Corrigendum 2 `keysort/2` variable and
113
112
  non-pair errors are corrected. Strict arithmetic no longer exposes the
114
113
  EyeProlog-only evaluable atom `e`, while the Corrigendum arithmetic additions
115
- remain available. These corrections narrow the remaining `audit` rows but do
116
- not by themselves close the full shall-by-shall/error-condition exit criteria.
114
+ remain available. These corrections are retained as regression evidence inside the closed shall-by-shall/error-condition audit.
117
115
 
118
116
  The next Corrigendum 2 pass closed the prescribed `call/2..8` max-arity
119
117
  branch for processors with a finite `max_arity`, and corrected reverse
120
- `atom_chars/2` / `atom_codes/2` improper-list culprits. After issue #66 restored
121
- EyeProlog's selected `max_arity=unbounded`, the conditional `call/N`
118
+ `atom_chars/2` / `atom_codes/2` improper-list culprits. With EyeProlog's selected `max_arity=unbounded`, the conditional `call/N`
122
119
  `representation_error(max_arity)` branch is intentionally unreachable unless a
123
120
  future processor profile selects a finite compound-term limit; closure
124
121
  expansion itself remains covered by strict regressions.
@@ -165,8 +162,7 @@ describes: a later `force(false)` does not cancel an earlier `force(true)` when
165
162
  a Resource Error or System Error occurs during closure. Focused strict tests
166
163
  cover both overlap families.
167
164
 
168
- The next row-audit tranche makes the remaining exit criterion concrete rather
169
- than leaving it as a broad test-count claim.
165
+ The row-level matrices make the exit criteria concrete rather than leaving conformance as a broad test-count claim.
170
166
  [ISO-BUILTIN-MODE-ERROR-MATRIX.md](ISO-BUILTIN-MODE-ERROR-MATRIX.md) now records
171
167
  each prescribed mode/error row for the 8.2-8.5 and 8.15-8.17 slices, and
172
168
  [ISO-PROCESSOR-REQUIREMENTS.md](ISO-PROCESSOR-REQUIREMENTS.md) decomposes the
@@ -206,9 +202,7 @@ individual-error outcomes in `ISO-BUILTIN-MODE-ERROR-MATRIX.md`. During this
206
202
  pass `stream_property/2` exposed a lifecycle distinction: a syntactically valid
207
203
  stream-term for a stream that has been closed denotes no currently open stream
208
204
  property pair and therefore fails, whereas a term that is not a stream-term is
209
- still a `domain_error(stream, ...)`. This leaves the remaining #65 checklist focused on Clause 6 syntax/rejection,
210
- higher-level 7.10 stream semantics, residual 7.12 processor errors, and final
211
- unexplained-deviation closure rather than unmapped built-in tables.
205
+ still a `domain_error(stream, ...)`. The higher-level Clause 6, 7.10, and 7.12 gates now close those surrounding processor requirements as well, so the built-in table participates in a fully dispositioned release-facing ledger.
212
206
 
213
207
  ## Post-Corrigendum STC cross-check
214
208
 
@@ -224,7 +218,7 @@ type precedence, `read_term/3` EOF handling, mixed arithmetic comparison,
224
218
  and `bagof/3` answer order. STC #21 is also used to keep finite-host exhaustion
225
219
  of unbounded integer operations inside the Prolog resource-error model.
226
220
 
227
- Issue #66 corresponds to the newer STC arity discussion: `max_arity` describes
221
+ The newer STC arity discussion clarifies that `max_arity` describes
228
222
  compound terms. EyeProlog therefore selects `unbounded` and does not invent a
229
223
  finite predicate/procedure ceiling merely to preserve the former 65535 value.
230
224
  STC #56, which became a WG17 action item, is implemented narrowly for database
@@ -284,25 +278,25 @@ outputs are never auto-accepted.
284
278
 
285
279
  ## Exit criteria for a full conformance claim
286
280
 
287
- Issue #65 is closed by explicit dispositions, not by a test-count threshold.
288
- The remaining qualification can be removed only when every open item below is
289
- closed without an unexplained deviation from the published Part 1 + Corrigenda
290
- baseline. Public post-N289 STC drafts remain review input until standardized.
281
+ The Part 1 audit is closed by explicit dispositions, not by a test-count threshold.
282
+ The table below records the closure criteria used by the project. A `covered`
283
+ status is an implementation/audit result, not an independent certification. Public
284
+ post-N289 STC drafts remain review input until standardized.
291
285
 
292
- | Criterion | Status | Evidence / remaining work |
286
+ | Criterion | Status | Evidence |
293
287
  | --- | --- | --- |
294
- | Clause 5 processor obligations have explicit dispositions | open | `ISO-PROCESSOR-REQUIREMENTS.md` still depends on the remaining Clause 6 preparation/rejection and syntax-preservation work |
295
- | Clause 6 lexical/syntactic requirements have explicit dispositions | open | the 366-case vendored WG17 syntax gate and cross-profile preservation are green; the remaining work is the production-by-production shall/rejection map |
296
- | Clause 7 semantic requirements have explicit dispositions | open | 7.1-7.9 and 7.11 are closed; higher-level 7.10 stream semantics and residual processor-level 7.12 requirements remain |
288
+ | 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. |
289
+ | Clause 6 lexical/syntactic requirements have explicit dispositions | covered | the strict Clause 6 production/rejection gate and the 366-case vendored WG17 matrix cover the standard families; cross-profile preservation verifies that normal extensions do not reinterpret strict-accepted text. |
290
+ | 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. |
297
291
  | Clause 8 built-in modes/errors have explicit dispositions | covered | `ISO-BUILTIN-MODE-ERROR-MATRIX.md` closes 8.2-8.17 row by row |
298
292
  | 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 |
299
293
  | Implementation-defined choices are documented | covered | `ISO-IMPLEMENTATION-DEFINED.md` is the Clause 5.4 decision index and strict tests pin execution-visible choices |
300
- | Implementation-specific strict/normal boundary is documented and tested | open | the major 5.5 hooks are closed; exhaustive 5.5.1 syntax preservation remains tied to the Clause 6 audit |
294
+ | Implementation-specific strict/normal boundary is documented and tested | covered | all 5.5 hooks have explicit dispositions; the WG17 cross-profile gate verifies syntax-preservation for standard text accepted by the strict reader. |
301
295
  | Published Corrigenda 1-3 are incorporated | covered | dedicated conformance/strict tests and this ledger track all three published Corrigenda |
302
296
  | Current post-N289 draft is tracked without silently changing the published baseline | covered | `STC-DRAFT-STATUS.md` tracks reviewed draft items separately from normative requirements |
303
297
  | Independent external syntax corpus is an offline release gate | covered | the vendored WG17 syntax matrix has 366 executable dispositions checked against its upstream expectations |
304
298
  | Third-party standard-core regression provenance is retained | covered | adapted Logtalk, Scryer, Trealla, and SWI-Prolog cases retain source identifiers and licenses in `THIRD_PARTY.md` |
305
- | No unexplained deviation remains in the release-facing ledger | open | every remaining `audit` row must end as covered, implementation-defined/specific with documented behavior, not applicable, or a documented defect |
299
+ | No unexplained deviation remains in the release-facing ledger | covered | the release-facing ledger contains no remaining `audit` rows; documented variation points are implementation-defined/specific or draft-only rather than unexplained deviations. |
306
300
 
307
301
  The specialized row matrices are evidence for this ledger, not separate public
308
302
  status documents. *The Art of EyeProlog* remains the implementation reference.
@@ -85,7 +85,6 @@ unbounded integer model and translate finite-host exhaustion to
85
85
  ## Closure note
86
86
 
87
87
  With this matrix and the strict arithmetic regression, the release-facing
88
- Clause 7.9 and Clause 9 rows are `covered`. The remaining issue #65 audit is not
89
- therefore an arithmetic audit: it is concentrated in Clause 6 text/rejection,
90
- Clause 7.4-7.8 and 7.10/7.12 processor semantics, their Clause 5 dependencies,
91
- and the remaining processor-level exit criteria.
88
+ Clause 7.9 and Clause 9 rows are `covered`. The surrounding processor and syntax
89
+ requirements are dispositioned in `ISO-PROCESSOR-REQUIREMENTS.md` and
90
+ `ISO-COMPLIANCE.md`.
@@ -65,7 +65,7 @@ Status values are:
65
65
  | 9.1.3.1 | Integer division rounding function `rndI` | Truncation toward zero, matching the `integer_rounding_function=toward_zero` flag. | **defined** — BigInt division for `//` in `src/iso-arithmetic.js`. |
66
66
  | 7.11.2.1 | Whether preparation-time `Convc` affects execution-time `Convc` | Yes: mappings created while Prolog text is prepared are retained and initialize the solver's execution-time conversion map. | **defined** — `src/parser.js`, `src/program.js`, `src/solver.js`. |
67
67
  | 7.11.2.2 | Effect when `debug=on` | The flag is accepted and stored; it does not change goal semantics or enable a debugger. | **defined** — `src/solver.js`; no semantic branch depends on `debug`. |
68
- | 7.11.2.3 | Default `max_arity` | `unbounded`: EyeProlog imposes no fixed semantic ceiling on compound-term arity. Practical host allocation exhaustion is a resource condition. This flag is distinct from any potential implementation-specific procedure-arity limit; EyeProlog currently declares no separate finite procedure limit. | **defined** — `src/iso-limits.js`, `src/solver.js`, `src/parser.js`, `src/iso.js`; issue #66 regression coverage. |
68
+ | 7.11.2.3 | Default `max_arity` | `unbounded`: EyeProlog imposes no fixed semantic ceiling on compound-term arity. Practical host allocation exhaustion is a resource condition. This flag is distinct from any potential implementation-specific procedure-arity limit; EyeProlog currently declares no separate finite procedure limit. | **defined** — `src/iso-limits.js`, `src/solver.js`, `src/parser.js`, `src/iso.js`; strict regression coverage. |
69
69
  | 7.11.2.5 | Default `double_quotes` | `chars`. | **defined** — `src/solver.js`, parser flag state. |
70
70
  | 7.12.1 | Second argument of `error/2` | The default context term is the atom `eyeprolog`. A few implementation-specific diagnostics may deliberately supply a more specific context term. | **defined** — `formalErrorTerm()` in `src/iso.js`. |
71
71
  | 7.12.2(f) | Implementation-defined representation limits | Character and character-code operations are limited to Unicode scalar values; surrogates and values above U+10FFFF are representation errors. Arity/integer values are modeled as unbounded but may hit host/resource limits. Float input overflow uses the implementation-specific `max_float`/`min_float` representation names documented by the STC-oriented tests. | **defined** — parser/ISO numeric and character guards. |
@@ -83,7 +83,7 @@ Status values are:
83
83
  | 9.4.5 | Bitwise complement | BigInt complement, i.e. `~N = -N-1`. | **defined** — `~a`. |
84
84
  | Cor.2 9.4.6 | `xor/2` with negative operands | BigInt infinite-two's-complement semantics. | **defined** — `a ^ b`. |
85
85
 
86
- ### Issue #56: one underflow policy
86
+ ### Floating underflow policy
87
87
 
88
88
  Clause 9.1.4.2 permits the processor to choose `round(x)` or the exceptional
89
89
  value `underflow` for a tiny non-zero result when an operation is governed by
@@ -7,27 +7,26 @@ extension boundary visible as its own auditable row.
7
7
 
8
8
  The normative baseline is ISO/IEC 13211-1:1995 plus Technical Corrigenda 1-3.
9
9
  `covered` means the requirement has an implementation/documentation decision
10
- and executable evidence. `audit` means the implementation has relevant tests
11
- but the project has not yet reduced every dependent Clause 6-9 requirement to
12
- an explicit pass/not-applicable decision. No row here is an independent
10
+ and executable evidence. `not applicable` records a standard variation that does
11
+ not apply to EyeProlog's selected processor profile. No row here is an independent
13
12
  certification claim.
14
13
 
15
14
  ## 5.1 — conforming processor obligations
16
15
 
17
- | Requirement | Status | Current evidence / remaining work |
16
+ | Requirement | Status | Current evidence |
18
17
  | --- | --- | --- |
19
- | 5.1(a) prepare conforming Prolog text | audit | parser/preparation tests, the closed 7.4 directive/source-clause matrix, include/ensure-loaded behavior, preparation-time operators/flags/character conversion, and the complete vendored WG17 syntax matrix; the remaining dependency is the production-by-production Clause 6 map |
20
- | 5.1(b) execute conforming Prolog goals | audit | the 7.1-7.8 term/preparation/database/control matrices, 7.9/Clause 9 evaluable-functor matrix, and complete 8.2-8.17 built-in row audit are closed; remaining dependency rows are higher-level 7.10 and residual processor-level 7.12 semantics |
21
- | 5.1(c) reject nonconforming text/read terms | audit | syntax-error corpus, WG17 negative syntax cases, strict extension rejection; exhaustive Clause 6 rejection mapping remains open |
18
+ | 5.1(a) prepare conforming Prolog text | covered | the strict Clause 6 production/rejection gate, complete vendored WG17 syntax matrix, and closed 7.4 preparation/directive matrix cover text recognition and preparation |
19
+ | 5.1(b) execute conforming Prolog goals | covered | 7.1-7.12 semantics, all 8.2-8.17 built-in rows, and Clause 9 evaluable functors have explicit executable dispositions |
20
+ | 5.1(c) reject nonconforming text/read terms | covered | WG17 negative cases plus focused malformed token, list, operator, argument, escape, comment, and extension-syntax cases exercise rejection across the Clause 6 families |
22
21
  | 5.1(d) specify permitted variations | covered | `ISO-IMPLEMENTATION-DEFINED.md` records the Part 1 implementation-defined choices and implementation-specific extension families |
23
22
  | 5.1(e) offer a strictly conforming mode | covered | CLI `--iso-strict` and API `isoStrict: true`; registry/directive/operator/flag extension filtering plus disabled implementation-specific execution shortcuts |
24
23
 
25
24
  ## 5.2-5.4 — text, goals, and documentation
26
25
 
27
- | Requirement | Status | Current evidence / remaining work |
26
+ | Requirement | Status | Current evidence |
28
27
  | --- | --- | --- |
29
- | 5.2 conforming and strictly conforming Prolog text boundary | audit | strict parser accepts Part 1 + Corrigenda syntax plus implementation-defined PCS choices and rejects implementation-specific language facilities; 7.4 preparation is closed and the full Clause 6 production/rejection map remains open |
30
- | 5.3 conforming and strictly conforming Prolog goal boundary | audit | strict registry/control/evaluable filtering plus closed 7.1-7.9 and 8.2-8.17 row matrices; remaining higher-level 7.10 stream and processor-error semantics keep the top-level goal boundary open |
28
+ | 5.2 conforming and strictly conforming Prolog text boundary | covered | strict parsing/preparation accepts the Part 1 + Corrigenda language under the documented PCS choices and rejects implementation-specific language facilities; normal-profile preservation is checked against every strict-accepted WG17 case |
29
+ | 5.3 conforming and strictly conforming Prolog goal boundary | covered | strict registry/control/evaluable filtering plus closed 7.1-7.12, 8.2-8.17, and Clause 9 audits define the goal boundary |
31
30
  | 5.4 accompanying documentation for implementation-defined and implementation-specific features | covered | `ISO-IMPLEMENTATION-DEFINED.md`, *The Art of EyeProlog*, strict-boundary documentation, and release-facing conformance ledgers |
32
31
 
33
32
  ## 5.5 — extension boundaries
@@ -35,7 +34,7 @@ certification claim.
35
34
  | Requirement | Status | EyeProlog decision / evidence |
36
35
  | --- | --- | --- |
37
36
  | 5.5 general extension rule | covered | normal mode may provide documented extensions; strict mode removes their Part 1 interpretation rather than changing implementation-defined choices |
38
- | 5.5.1 syntax extensions preserve standard token/text meaning | audit | WG17 syntax is a release gate and strict mode removes module/DCG/quad interpretation. Every vendored WG17 case that succeeds in the Part 1 strict reader now has an identical normal-profile observable outcome, directly checking that normal syntax extensions do not reinterpret accepted standard text. A complete one-row preservation map for every Clause 6 production remains open |
37
+ | 5.5.1 syntax extensions preserve standard token/text meaning | covered | WG17 syntax is a release gate and strict mode removes module/DCG/quad interpretation. Every vendored WG17 case that succeeds in the strict reader has the same observable outcome in normal mode; the focused Clause 6 gate separately covers each standard token/term family and malformed counterparts. |
39
38
  | 5.5.2 additional predefined operators | covered | strict mode starts from the Part 1 predefined operator table; normal-profile extra operators are documented and filtered |
40
39
  | 5.5.3 initial character-conversion mapping | covered | identity initial mapping; user changes are exercised through preparation/execution `char_conversion/2` behavior |
41
40
  | 5.5.4 additional term types | covered | the normal JavaScript API's `stringTerm(Text)` is documented as an implementation-specific sixth term type, including disjointness, ordering, clause conversion, lack of source token syntax, expression behavior, and writing; strict program/goal entry rejects that type with `representation_error(term)` |
@@ -47,10 +46,26 @@ certification claim.
47
46
  | 5.5.10 additional evaluable functors/types | covered | strict mode rejects the normal-profile evaluable `e` extension while retaining the full Part 1 + Corrigenda arithmetic set. `ISO-EVALUABLE-FUNCTOR-MATRIX.md` now closes the Clause 9 semantic/error audit and pins the 9.1.4.2 `resultF`, mixed-type `max/2`/`min/2`, and signed bitwise/shift choices. Post-N289 STC #75 remains separate from the published baseline |
48
47
  | 5.5.11 reserved atoms | not applicable | EyeProlog declares no reserved-atom extension; extension names remain ordinary atoms unless used in a documented syntactic/predicate/directive role |
49
48
 
49
+ ## Clause 6 syntax-preservation closure
50
+
51
+ The production audit is kept here rather than in another status file. The strict
52
+ regression gate covers the following families directly, while the complete WG17
53
+ matrix supplies the detailed independent syntax cases.
54
+
55
+ | Clause family | Disposition | Executable evidence |
56
+ | --- | --- | --- |
57
+ | 6.2 Prolog text/data boundary | covered | complete-term parsing, end-token/boundary rejection, preparation tests |
58
+ | 6.3.1-6.3.3 atomic, variable, functional compound terms | covered | atoms, integers/floats, negative numbers, variables, functional arguments |
59
+ | 6.3.4 operator notation | covered | precedence/associativity/operator-table tests plus invalid `xfx` chaining |
60
+ | 6.3.5-6.3.7 list, curly and double-quoted notation | covered | list tails, curly terms, `double_quotes` behavior and read/write round trips |
61
+ | 6.4.1-6.4.8 tokens | covered | layout/comments, quoted escapes, names, integer bases/character codes, floats, double-quoted tokens, solo/meta tokens, malformed counterparts |
62
+ | 6.5 processor characters | covered | documented Unicode-scalar PCS and lexical classes, invalid-scalar representation errors |
63
+ | 6.6 collating sequence | covered | Unicode scalar value collation, atom-order regressions |
64
+ | 5.5.1 preservation under extensions | covered | every WG17 case accepted in strict mode has the same observable result in normal mode |
65
+
50
66
  ## Exit-use rule
51
67
 
52
- A top-level row stays `audit` until all of the normative clauses it depends on
53
- have explicit pass, not-applicable, or documented implementation-defined
54
- outcomes. `ISO-COMPLIANCE.md` records the same dependency closure in its embedded
55
- release-exit checklist. This prevents a large green regression suite from
56
- being mistaken for a completed processor-requirement audit.
68
+ All top-level rows now have covered, not-applicable, or documented
69
+ implementation-defined outcomes. `ISO-COMPLIANCE.md` records the same closure in
70
+ its embedded release-exit checklist. The green suite is evidence for those
71
+ dispositions; it is not presented as independent certification.
@@ -24,13 +24,10 @@ review evidence, not normative ISO claims.
24
24
  profile and implementation extensions. The default registry covers the exact
25
25
  predicate indicators listed in Appendix B of the book across the Part 1 strict-core
26
26
  target and the normal-mode module/DCG compatibility families. [ISO-COMPLIANCE.md](ISO-COMPLIANCE.md) is the explicit
27
- release-facing ledger for the Part 1 strict-core audit. This suite is
28
- still not an independent certification of every processor requirement or lexical
29
- edge. The complete 8.2-8.17 built-in family and Clause 7.1-7.9 term,
30
- preparation/database/control, and expression/evaluable-functor families are now
31
- tracked and closed at row level. The remaining Clause 6, higher-level
32
- 7.10/7.12, processor-dependency, and unexplained-deviation criteria stay
33
- explicitly open in the dedicated audit files. Public comparison material used during the audit remains supporting review
27
+ release-facing ledger for the Part 1 strict-core audit. This suite is not an independent certification. The release-facing Part 1
28
+ ledger now has explicit dispositions for Clause 5 processor obligations, Clause 6
29
+ syntax/rejection, Clause 7 semantics, the complete 8.2-8.17 built-in family, and
30
+ Clause 9 evaluable functors. Public comparison material remains supporting review
34
31
  evidence rather than a duplicated vendored corpus. Cases under `iso/`
35
32
  identify standards-derived behavior; other directories cover EyeProlog host
36
33
  contracts and extensions. EyeProlog-only execution features such as automatic
@@ -32,23 +32,22 @@ regressions.
32
32
  | [#49](https://www.complang.tuwien.ac.at/ulrich/iso-prolog/stc#49) | `read_term/3` and EOF | Covered by strict reader/conformance tests and the interactive-read regressions. |
33
33
  | [#50](https://www.complang.tuwien.ac.at/ulrich/iso-prolog/stc#50) | mixed integer/float arithmetic comparison | The STC-facing normal-profile case requires exact cross-type ordering and `max/2`/`min/2` use the same comparison. `--iso-strict` deliberately retains the published Part 1 integer-to-float comparison rule; the draft case is not silently substituted for that normative baseline. |
34
34
  | [#55](https://www.complang.tuwien.ac.at/ulrich/iso-prolog/stc#55) | integer rounding function | Existing flag conformance verifies `integer_rounding_function = toward_zero`. |
35
- | [#56](https://www.complang.tuwien.ac.at/ulrich/iso-prolog/stc#56) | protect `(:-)/1` and `(:-)/2` from database modification | **Found a gap during the #65 audit.** Strict database operations now treat both functors as static/private for `assert*`, `retract*`, `abolish/1`, declarations, and `clause/2`, while ordinary calls still follow the separate procedure-existence behavior described by the STC item. |
35
+ | [#56](https://www.complang.tuwien.ac.at/ulrich/iso-prolog/stc#56) | protect `(:-)/1` and `(:-)/2` from database modification | **The audit found a gap.** Strict database operations now treat both functors as static/private for `assert*`, `retract*`, `abolish/1`, declarations, and `clause/2`, while ordinary calls still follow the separate procedure-existence behavior described by the STC item. |
36
36
  | [#58](https://www.complang.tuwien.ac.at/ulrich/iso-prolog/stc#58) | `set_prolog_flag/2` instantiation error | Existing strict/error coverage requires an instantiation error when a required flag value is a variable. |
37
37
  | [#67](https://www.complang.tuwien.ac.at/ulrich/iso-prolog/stc#67) | `bagof/3` answer-order example | `stc/bagof_answer_order` verifies the proposed clarifying example produces `[2,1]`. |
38
38
  | [#68](https://www.complang.tuwien.ac.at/ulrich/iso-prolog/stc#68) | division examples | Existing arithmetic coverage evaluates signed integer `/` through the floating operation; no implementation-defined signed-division result is used. |
39
- | [#69](https://www.complang.tuwien.ac.at/ulrich/iso-prolog/stc#69) | arithmetic example culprit | **Found a #65 gap.** Strict expression evaluation now applies 7.9.2(c) to an atomic subexpression such as `foo`: it reports `type_error(evaluable,foo/0)` rather than the misleading `type_error(number,foo)` shown by the old 9.1.7 example. |
40
- | [#70](https://www.complang.tuwien.ac.at/ulrich/iso-prolog/stc#70) | optional `max_procedure_arity` | Reviewed after issue #66 corrected the earlier #71 pointer. EyeProlog has no declared procedure-arity limit smaller than its `max_arity=unbounded` term model, so the implementation-defined optional flag is intentionally absent. |
39
+ | [#69](https://www.complang.tuwien.ac.at/ulrich/iso-prolog/stc#69) | arithmetic example culprit | **The audit found a gap.** Strict expression evaluation now applies 7.9.2(c) to an atomic subexpression such as `foo`: it reports `type_error(evaluable,foo/0)` rather than the misleading `type_error(number,foo)` shown by the old 9.1.7 example. |
40
+ | [#70](https://www.complang.tuwien.ac.at/ulrich/iso-prolog/stc#70) | optional `max_procedure_arity` | Reviewed after the STC arity discussion corrected the earlier #71 pointer. EyeProlog has no declared procedure-arity limit smaller than its `max_arity=unbounded` term model, so the implementation-defined optional flag is intentionally absent. |
41
41
  | [#72](https://www.complang.tuwien.ac.at/ulrich/iso-prolog/stc#72) | tentative non-ground stream-term instances | Reviewed as a tentative post-2026 proposal. EyeProlog does not make this draft wording normative in `--iso-strict`; the published Part 1 stream-term/domain rules remain the baseline until WG17 settles the proposal. |
42
42
  | [#73](https://www.complang.tuwien.ac.at/ulrich/iso-prolog/stc#73) | `read/1-2` and `read_term/2-3` representation limits | The 2026-08-23 post-N289 draft now explicitly proposes `max_float` / `min_float` alongside the existing representation-limit flags. EyeProlog already reports those errors while reading overflowing positive/negative float tokens; strict regression coverage now exercises both `read/1` and `read_term/2`, and the literal STC cases pin parser preparation. |
43
43
  | [#74](https://www.complang.tuwien.ac.at/ulrich/iso-prolog/stc#74) | `number_chars/2` and `number_codes/2` representation limits | Positive and negative overflow now have explicit draft-facing cases for both conversion predicates, reporting `representation_error(max_float)` / `representation_error(min_float)` rather than a syntax error. |
44
44
  | [#75](https://www.complang.tuwien.ac.at/ulrich/iso-prolog/stc#75) | power underflow versus the 9.1.4.2 `resultF` choice | The draft proposes making the Part 1 `**/2` and Corrigendum 2 `^/2` underflow rows conditional on the implementation-defined `resultF` underflow choice. EyeProlog's published-baseline strict mode intentionally retains the currently published unconditional power-underflow clauses; its separate 9.1.4.2 choice remains `round(x)`. This proposal is tracked, not silently adopted. |
45
45
  | [#76](https://www.complang.tuwien.ac.at/ulrich/iso-prolog/stc#76) | `read/1-2` and `read_term/2-3` invalid input entity | Existing file-stream regressions already require `representation_error(character)` for invalid UTF-8 through all four read/read_term arities. The regression is now cross-referenced to the new draft item. |
46
- | [issue #54](https://github.com/eyereasoner/eyeprolog/issues/54) | float input range and underflow background | The earlier EyeProlog issue remains useful background for finite-double input overflow/underflow. Its overflow cases are now tracked by STC #73/#74; input underflow remains a separate implementation-profile check and must not be conflated with STC #75's power-underflow proposal. |
47
46
 
48
- ## Float-reading note from issue #54
47
+ ## Float-reading implementation note
49
48
 
50
49
  EyeProlog currently has a finite-double numeric profile. The draft-facing cases
51
- record the behavior discussed in issue #54:
50
+ record EyeProlog's finite-double behavior:
52
51
 
53
52
  - a positive finite numeric token beyond the representable range raises
54
53
  `representation_error(max_float)`;
@@ -69,7 +68,6 @@ how power underflow relates to the implementation-defined `resultF` choice.
69
68
  Relevant background:
70
69
 
71
70
  - [WG17 float update](https://www.complang.tuwien.ac.at/ulrich/iso-prolog/core_update_float-2014-07-21)
72
- - [Issue #54](https://github.com/eyereasoner/eyeprolog/issues/54)
73
71
 
74
72
  ## Maintenance rule
75
73
 
@@ -2,7 +2,7 @@
2
2
  // Release gate for the ISO/IEC 13211-1 strict-core execution profile.
3
3
  // This is intentionally separate from the broader `iso/` corpus because that
4
4
  // corpus also exercises Part 2 modules and Part 3 grammar rules.
5
- import { mkdtempSync, rmSync, writeFileSync } from 'node:fs';
5
+ import { mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
6
6
  import { tmpdir } from 'node:os';
7
7
  import { join } from 'node:path';
8
8
 
@@ -184,6 +184,56 @@ export function runIsoStrict(reporter = new TestReporter()) {
184
184
  equal(strict.stats.completed_goal_lists, 1, 'strict Unicode char_code/2');
185
185
  });
186
186
 
187
+ reporter.test('closes the Clause 6 syntax production and rejection rows', () => {
188
+ const accepted = [
189
+ ['p(a).', '6.3.1 atom'],
190
+ ['p(123).', '6.3.1 integer'],
191
+ ['p(1.5).', '6.3.1 float'],
192
+ ['p(-1).', '6.3.1 negative integer'],
193
+ ['p(-1.5).', '6.3.1 negative float'],
194
+ ['p(X,_,_).', '6.3.2 variables'],
195
+ ['p(f(a,b)).', '6.3.3 functional compound'],
196
+ ['p((a+b*c)).', '6.3.4 operator notation'],
197
+ ['p([a,b|T]).', '6.3.5 list notation'],
198
+ ['p({a}).', '6.3.6 curly term'],
199
+ ['p("ab").', '6.3.7/6.4.6 double quoted list'],
200
+ ['% line comment\np(a).', '6.4.1 layout and line comment'],
201
+ ['/* block comment */ p(a).', '6.4.1 bracketed comment'],
202
+ ["p('a\\n').", '6.4.2 quoted character escape'],
203
+ ['p(0b101).', '6.4.4 binary integer'],
204
+ ['p(0o17).', '6.4.4 octal integer'],
205
+ ['p(0x1f).', '6.4.4 hexadecimal integer'],
206
+ ["p(0'a).", '6.4.4 character-code integer'],
207
+ ['p(1.2e3).', '6.4.5 exponent float'],
208
+ ['p(!).', '6.4.8 solo token'],
209
+ ];
210
+ for (const [source, label] of accepted) {
211
+ equal(parseProgramText(source, { isoStrict: true }).length, 1, label);
212
+ }
213
+
214
+ const rejected = [
215
+ ['p(`x`).', '6.4.7 back quoted string has no Part 1 token'],
216
+ ["p('x).", 'unterminated quoted token'],
217
+ ['p([a|b,c]).', 'invalid list production'],
218
+ ['p((1 = 2 = 3)).', 'invalid xfx associativity'],
219
+ ['p(a).x', 'end character requires a token boundary'],
220
+ ['p(1.0e).', 'malformed floating point token'],
221
+ ['p(a b).', 'adjacent alphanumeric tokens need separation/grammar'],
222
+ ['p(a,,b).', 'invalid argument production'],
223
+ ['/* unterminated', 'unterminated bracketed comment'],
224
+ ["p('\\x').", 'invalid hexadecimal escape'],
225
+ ];
226
+ for (const [source, label] of rejected) {
227
+ let threw = false;
228
+ try {
229
+ parseProgramText(source, { isoStrict: true });
230
+ } catch (_) {
231
+ threw = true;
232
+ }
233
+ equal(threw, true, label);
234
+ }
235
+ });
236
+
187
237
  reporter.test('rejects the normal-profile string term extension at strict API boundaries', () => {
188
238
  const normalSolver = new Solver(Program.parse(''), {});
189
239
  const normalGoal = compound('=', [stringTerm('x'), stringTerm('x')]);
@@ -472,6 +522,92 @@ export function runIsoStrict(reporter = new TestReporter()) {
472
522
  ], new Env(), 0)].length, 1, 'set_stream_position/2 successful mode');
473
523
  });
474
524
 
525
+ reporter.test('closes the higher-level ISO 7.10 stream model rows', () => {
526
+ const directory = mkdtempSync(join(tmpdir(), 'eyeprolog-iso-710-'));
527
+ const atomPath = (value) => `'${String(value).replaceAll("'", "''")}'`;
528
+ try {
529
+ const inputPath = join(directory, 'input.txt');
530
+ writeFileSync(inputPath, 'ab');
531
+ equal(run('', {
532
+ isoStrict: true,
533
+ goal: [
534
+ `open(${atomPath(inputPath)},read,S,[alias(tmp_in),reposition(true),eof_action(eof_code)])`,
535
+ '\\+ atom(S)',
536
+ 'stream_property(S,input)',
537
+ 'stream_property(S,alias(tmp_in))',
538
+ 'stream_property(S,reposition(true))',
539
+ 'stream_property(S,eof_action(eof_code))',
540
+ 'set_input(tmp_in)',
541
+ "get_char('a')",
542
+ 'close(tmp_in)',
543
+ 'current_input(C)',
544
+ 'stream_property(C,alias(user_input))',
545
+ 'catch(set_input(tmp_in),error(existence_error(stream,tmp_in),eyeprolog),true)',
546
+ ].join(','),
547
+ }).stats.completed_goal_lists, 1, 'stream-term, alias lifetime, target/current input, and close fallback');
548
+
549
+ const truncatePath = join(directory, 'truncate.txt');
550
+ writeFileSync(truncatePath, 'old');
551
+ equal(run('', {
552
+ isoStrict: true,
553
+ goal: `open(${atomPath(truncatePath)},write,S,[]),close(S)`,
554
+ }).stats.completed_goal_lists, 1, 'write open/close succeeds');
555
+ equal(readFileSync(truncatePath, 'utf8'), '', 'write mode empties an existing sink');
556
+
557
+ const appendPath = join(directory, 'append.txt');
558
+ writeFileSync(appendPath, 'ab');
559
+ equal(run('', {
560
+ isoStrict: true,
561
+ goal: `open(${atomPath(appendPath)},append,S,[reposition(true)]),put_char(S,c),set_stream_position(S,1),put_char(S,'Z'),close(S)`,
562
+ }).stats.completed_goal_lists, 1, 'append and repositioned output succeed');
563
+ equal(readFileSync(appendPath, 'utf8'), 'aZc', 'append starts at end and repositioned output overwrites');
564
+
565
+ const optionsPath = join(directory, 'options.txt');
566
+ writeFileSync(optionsPath, 'x');
567
+ equal(run('', {
568
+ isoStrict: true,
569
+ goal: [
570
+ `open(${atomPath(optionsPath)},read,S,[type(binary),type(text),reposition(false),reposition(true),eof_action(error),eof_action(eof_code)])`,
571
+ 'stream_property(S,type(text))',
572
+ 'stream_property(S,reposition(true))',
573
+ 'stream_property(S,eof_action(eof_code))',
574
+ 'close(S)',
575
+ ].join(','),
576
+ }).stats.completed_goal_lists, 1, 'rightmost contradictory stream option applies');
577
+
578
+ const binaryPath = join(directory, 'roundtrip.bin');
579
+ equal(run('', {
580
+ isoStrict: true,
581
+ goal: [
582
+ `open(${atomPath(binaryPath)},write,W,[type(binary)])`,
583
+ 'put_byte(W,0)',
584
+ 'put_byte(W,255)',
585
+ 'close(W)',
586
+ `open(${atomPath(binaryPath)},read,R,[type(binary)])`,
587
+ 'get_byte(R,0)',
588
+ 'get_byte(R,255)',
589
+ 'get_byte(R,-1)',
590
+ 'close(R)',
591
+ ].join(','),
592
+ }).stats.completed_goal_lists, 1, 'binary stream round-trip is byte exact');
593
+ equal([...readFileSync(binaryPath)].join(','), '0,255', 'binary sink contains exactly the output bytes');
594
+
595
+ const textPath = join(directory, 'text.txt');
596
+ equal(run('', {
597
+ isoStrict: true,
598
+ goal: `open(${atomPath(textPath)},write,S,[]),put_char(S,a),flush_output(S),close(S)`,
599
+ }).stats.completed_goal_lists, 1, 'text flush/close succeeds');
600
+ equal(readFileSync(textPath, 'utf8'), 'a', 'flush/close does not synthesize a final newline');
601
+
602
+ equal(run('', {
603
+ isoStrict: true,
604
+ goal: 'current_input(I),close(I),current_input(I),current_output(O),close(O),current_output(O)',
605
+ }).stats.completed_goal_lists, 1, 'standard streams remain open when close/1 is called');
606
+ } finally {
607
+ rmSync(directory, { recursive: true, force: true });
608
+ }
609
+ });
610
+
475
611
  reporter.test('closes the ISO 8.12-8.14 character, byte, and term-I/O rows', () => {
476
612
  const errors = [
477
613
  ['get_char(S,C)', 'instantiation_error', 'get_char/2 stream instantiation'],
@@ -611,6 +747,39 @@ export function runIsoStrict(reporter = new TestReporter()) {
611
747
  closeWith('[force(false),force(true)]');
612
748
  });
613
749
 
750
+ reporter.test('closes the ISO 7.12 processor error envelope and classification rows', () => {
751
+ const caught = [
752
+ "catch(atom_length(X,N),error(instantiation_error,eyeprolog),true)",
753
+ "catch(atom_length(1,N),error(type_error(atom,1),eyeprolog),true)",
754
+ "catch(op(1300,xfx,foo),error(domain_error(operator_priority,1300),eyeprolog),true)",
755
+ "catch(call(no_such_predicate),error(existence_error(procedure,no_such_predicate/0),eyeprolog),true)",
756
+ "catch(abolish(atom/1),error(permission_error(modify,static_procedure,atom/1),eyeprolog),true)",
757
+ "catch(char_code(C,1114112),error(representation_error(character_code),eyeprolog),true)",
758
+ "catch(X is 1/0,error(evaluation_error(zero_divisor),eyeprolog),true)",
759
+ "catch(X is 1<<4294967296,error(resource_error(memory),eyeprolog),true)",
760
+ ];
761
+ for (const goal of caught) {
762
+ equal(run('', { isoStrict: true, goal }).stats.completed_goal_lists, 1, goal);
763
+ }
764
+
765
+ equal(run('', {
766
+ isoStrict: true,
767
+ goal: "catch(read_term(T,[]),error(syntax_error(read_term),eyeprolog),true)",
768
+ ioOptions: { input: "'unterminated." },
769
+ }).stats.completed_goal_lists, 1, 'syntax error uses error/2 envelope and implementation-defined context');
770
+
771
+ const systemSolver = new Solver(Program.parse('', { isoStrict: true }), { isoStrict: true });
772
+ systemSolver.io.flush = () => { throw new Error('simulated host I/O failure'); };
773
+ equal([...systemSolver.solve([
774
+ parseGoalText('catch(flush_output(user_output),error(system_error,eyeprolog),true)', { isoStrict: true }),
775
+ ], new Env(), 0)].length, 1, 'system error uses error/2 envelope and implementation-defined context');
776
+
777
+ // ISO 7.12 deliberately leaves the choice implementation-dependent when
778
+ // several error conditions hold simultaneously. Existing overlap tests
779
+ // above pin EyeProlog's deterministic choices without treating table order
780
+ // as an additional normative requirement.
781
+ });
782
+
614
783
  reporter.test('follows Part 1 arithmetic type and exceptional errors', () => {
615
784
  const cases = [
616
785
  ["X is '+'(foo,77)", 'type_error(evaluable)', 'STC #69 simple arithmetic atom is foo/0'],
@@ -2221,22 +2221,16 @@ c4 ?- call((!;1)).
2221
2221
  {
2222
2222
  name: 'REPL term input is on demand in conjunctions and Ctrl-D does not exit the top level',
2223
2223
  run: () => {
2224
- if (process.platform === 'win32') return;
2225
- const available = spawnSync('sh', ['-c',
2226
- 'command -v script >/dev/null 2>&1 && script --version 2>/dev/null | grep -qi util-linux']);
2227
- if (available.status !== 0) return;
2228
- const command = `${shellQuote(process.execPath)} ${shellQuote(bin)}`;
2229
- const scriptCommand =
2230
- `{ printf 'read(X), read(Y).\n'; sleep 0.3; ` +
2231
- `printf 'foo.\n'; sleep 0.3; printf 'bar.\n'; sleep 0.3; ` +
2232
- `printf 'read(Z).\n'; sleep 0.3; printf '\\004'; sleep 0.3; ` +
2233
- `printf 'true.\n'; sleep 0.3; printf 'halt.\n'; } | ` +
2234
- `script -qefc ${shellQuote(command)} /dev/null`;
2235
- const result = spawnSync('sh', ['-c', scriptCommand], {
2236
- cwd: packageRoot,
2237
- encoding: 'utf8',
2238
- timeout: 5000,
2239
- });
2224
+ if (!hasUtilLinuxScript()) return;
2225
+ const result = runScriptedRepl([
2226
+ { waitFor: '?- ', send: 'read(X), read(Y).\n' },
2227
+ { waitFor: ' |: ', send: 'foo.\n' },
2228
+ { waitFor: '|: ', send: 'bar.\n' },
2229
+ { waitFor: 'X = foo, Y = bar.', send: 'read(Z).\n' },
2230
+ { waitFor: ' |: ', send: '\u0004' },
2231
+ { waitFor: 'Z = end_of_file.', send: 'true.\n' },
2232
+ { waitFor: ' true.', send: 'halt.\n' },
2233
+ ]);
2240
2234
  assertEqual(result.error?.code, undefined, 'interactive read timeout');
2241
2235
  assertEqual(result.status, 0, 'exit status');
2242
2236
  assertIncludes(result.stdout, 'X = foo, Y = bar.', 'conjunction reads');
@@ -2248,23 +2242,18 @@ c4 ?- call((!;1)).
2248
2242
  {
2249
2243
  name: 'REPL character input is on demand and Ctrl-D stays local (issue #55)',
2250
2244
  run: () => {
2251
- if (process.platform === 'win32') return;
2252
- const available = spawnSync('sh', ['-c',
2253
- 'command -v script >/dev/null 2>&1 && script --version 2>/dev/null | grep -qi util-linux']);
2254
- if (available.status !== 0) return;
2255
- const command = `${shellQuote(process.execPath)} ${shellQuote(bin)}`;
2256
- const scriptCommand =
2257
- `{ printf 'peek_char(P), get_char(C), get_code(K).\n'; sleep 0.3; ` +
2258
- `printf 'ab\n'; sleep 0.3; printf 'get_char(N).\n'; sleep 0.3; ` +
2259
- `printf 'z\n'; sleep 0.3; printf 'get_char(E).\n'; sleep 0.3; ` +
2260
- `printf '\\004'; sleep 0.3; printf 'get_char(D).\n'; sleep 0.3; ` +
2261
- `printf 'q\n'; sleep 0.3; printf 'halt.\n'; } | ` +
2262
- `script -qefc ${shellQuote(command)} /dev/null`;
2263
- const result = spawnSync('sh', ['-c', scriptCommand], {
2264
- cwd: packageRoot,
2265
- encoding: 'utf8',
2266
- timeout: 5000,
2267
- });
2245
+ if (!hasUtilLinuxScript()) return;
2246
+ const result = runScriptedRepl([
2247
+ { waitFor: '?- ', send: 'peek_char(P), get_char(C), get_code(K).\n' },
2248
+ { waitFor: ' |: ', send: 'ab\n' },
2249
+ { waitFor: 'P = a, C = a, K = 98.', send: 'get_char(N).\n' },
2250
+ { waitFor: ' |: ', send: 'z\n' },
2251
+ { waitFor: 'N = z.', send: 'get_char(E).\n' },
2252
+ { waitFor: ' |: ', send: '\u0004' },
2253
+ { waitFor: 'E = end_of_file.', send: 'get_char(D).\n' },
2254
+ { waitFor: ' |: ', send: 'q\n' },
2255
+ { waitFor: 'D = q.', send: 'halt.\n' },
2256
+ ]);
2268
2257
  assertEqual(result.error?.code, undefined, 'interactive character input timeout');
2269
2258
  assertEqual(result.status, 0, 'exit status');
2270
2259
  assertIncludes(result.stdout, 'P = a, C = a, K = 98.', 'peek/get char and code input');
@@ -3665,7 +3654,7 @@ function documentationSyncCases() {
3665
3654
  run: () => assertArrayEqual(documentationSourceStyleIssues(), [], 'documentation source style'),
3666
3655
  },
3667
3656
  {
3668
- name: 'DCG nonterminal indicator prose uses valid ... //0 spacing (issue #49)',
3657
+ name: 'DCG nonterminal indicator prose uses valid ... //0 spacing',
3669
3658
  run: () => {
3670
3659
  for (const filename of ['README.md', 'the-art-of-eyeprolog.md', 'src/standard-library.js', 'src/solver.js']) {
3671
3660
  const text = fs.readFileSync(path.join(packageRoot, filename), 'utf8');
@@ -3674,7 +3663,7 @@ function documentationSyncCases() {
3674
3663
  },
3675
3664
  },
3676
3665
  {
3677
- name: 'ISO 5.4 decision index inventories implementation-defined choices (issue #56)',
3666
+ name: 'ISO 5.4 decision index inventories implementation-defined choices',
3678
3667
  run: () => {
3679
3668
  const filename = path.join(testRoot, 'conformance', 'ISO-IMPLEMENTATION-DEFINED.md');
3680
3669
  const text = fs.readFileSync(filename, 'utf8');
@@ -3687,7 +3676,7 @@ function documentationSyncCases() {
3687
3676
  '8.17.3', '8.17.4', '9.1.3.1', '9.1.4.1', '9.1.4.2', '9.1.4.3', '9.4',
3688
3677
  '9.4.1', '9.4.2', '9.4.3', '9.4.4', '9.4.5', 'Cor.2 9.4.6',
3689
3678
  ]) assertIncludes(text, `| ${clause} |`, `ISO 5.4 clause ${clause}`);
3690
- assertIncludes(text, 'Issue #56: one underflow policy', 'issue #56 explanation');
3679
+ assertIncludes(text, 'Floating underflow policy', 'floating underflow policy explanation');
3691
3680
  assertIncludes(text, 'Implementation-specific features required to be documented by 5.4', '5.5 extension inventory');
3692
3681
  },
3693
3682
  },
@@ -3722,17 +3711,33 @@ function documentationSyncCases() {
3722
3711
  },
3723
3712
  },
3724
3713
  {
3725
- name: 'ISO exit criteria keep remaining audit work explicit',
3714
+ name: 'ISO Clause 6, 7.10, and 7.12 closure is documented',
3715
+ run: () => {
3716
+ const compliance = fs.readFileSync(path.join(testRoot, 'conformance', 'ISO-COMPLIANCE.md'), 'utf8');
3717
+ const processor = fs.readFileSync(path.join(testRoot, 'conformance', 'ISO-PROCESSOR-REQUIREMENTS.md'), 'utf8');
3718
+ for (const row of [
3719
+ '| Clause 6 — tokens, terms, lists, operators, quoted text | covered |',
3720
+ '| 7.10 — input/output concepts | covered |',
3721
+ '| 7.12 — errors | covered |',
3722
+ ]) assertIncludes(compliance, row, row);
3723
+ assertIncludes(processor, '## Clause 6 syntax-preservation closure', 'Clause 6 closure map');
3724
+ assertIncludes(processor, '| 5.5.1 syntax extensions preserve standard token/text meaning | covered |', '5.5.1 covered');
3725
+ },
3726
+ },
3727
+ {
3728
+ name: 'ISO release-facing exit criteria are explicitly closed',
3726
3729
  run: () => {
3727
3730
  const exit = fs.readFileSync(path.join(testRoot, 'conformance', 'ISO-COMPLIANCE.md'), 'utf8');
3728
3731
  for (const item of [
3729
- '| Clause 6 lexical/syntactic requirements have explicit dispositions | open |',
3730
- '| Clause 7 semantic requirements have explicit dispositions | open |',
3732
+ '| Clause 5 processor obligations have explicit dispositions | covered |',
3733
+ '| Clause 6 lexical/syntactic requirements have explicit dispositions | covered |',
3734
+ '| Clause 7 semantic requirements have explicit dispositions | covered |',
3731
3735
  '| Clause 8 built-in modes/errors have explicit dispositions | covered |',
3732
3736
  '| Clause 9 evaluable-functor requirements have explicit dispositions | covered |',
3733
3737
  '| Independent external syntax corpus is an offline release gate | covered |',
3734
- '| No unexplained deviation remains in the release-facing ledger | open |',
3738
+ '| No unexplained deviation remains in the release-facing ledger | covered |',
3735
3739
  ]) assertIncludes(exit, item, item);
3740
+ assertNotIncludes(exit, '| audit |', 'no release-facing audit rows remain');
3736
3741
  },
3737
3742
  },
3738
3743
  {
@@ -3749,7 +3754,17 @@ function documentationSyncCases() {
3749
3754
  assertIncludes(readme, 'implementation reference is [*The Art of EyeProlog*]', 'README book hand-off');
3750
3755
  assertIncludes(readme, 'test/conformance/ISO-COMPLIANCE.md', 'README concise audit link');
3751
3756
  assertEqual(readme.includes('2026-08-23 draft items #73-#76'), false, 'README omits audit-history detail');
3752
- assertIncludes(profile, 'completed row-level 7.1-7.9 term, preparation/database/control, and arithmetic audits', 'Why EyeProlog audit state');
3757
+ assertIncludes(profile, 'Part 1 processor, syntax, semantic, built-in, and arithmetic', 'Why EyeProlog audit state');
3758
+ },
3759
+ },
3760
+ {
3761
+ name: 'documentation avoids repository issue references',
3762
+ run: () => {
3763
+ for (const file of listMarkdownFiles(packageRoot)) {
3764
+ const text = fs.readFileSync(file, 'utf8');
3765
+ assertEqual(/github\.com\/eyereasoner\/eyeprolog\/issues\//.test(text), false, `${path.relative(packageRoot, file)} repository issue URL`);
3766
+ assertEqual(/\bissue\s+#\d+\b/i.test(text), false, `${path.relative(packageRoot, file)} repository issue number`);
3767
+ }
3753
3768
  },
3754
3769
  },
3755
3770
  {
@@ -6086,6 +6101,99 @@ function shellQuote(value) {
6086
6101
  return `'${String(value).replaceAll("'", "'\"'\"'")}'`;
6087
6102
  }
6088
6103
 
6104
+ let utilLinuxScriptAvailable = null;
6105
+
6106
+ function hasUtilLinuxScript() {
6107
+ if (process.platform === 'win32') return false;
6108
+ if (utilLinuxScriptAvailable == null) {
6109
+ const available = spawnSync('sh', ['-c',
6110
+ 'command -v script >/dev/null 2>&1 && script --version 2>/dev/null | grep -qi util-linux']);
6111
+ utilLinuxScriptAvailable = available.status === 0;
6112
+ }
6113
+ return utilLinuxScriptAvailable;
6114
+ }
6115
+
6116
+ function runScriptedRepl(steps, { timeout = 5000 } = {}) {
6117
+ const command = `${shellQuote(process.execPath)} ${shellQuote(bin)}`;
6118
+ const payload = Buffer.from(JSON.stringify({
6119
+ command,
6120
+ cwd: packageRoot,
6121
+ steps,
6122
+ timeout,
6123
+ })).toString('base64');
6124
+ const helper = String.raw`
6125
+ const { spawn } = require('node:child_process');
6126
+ const config = JSON.parse(Buffer.from(process.env.EYEPROLOG_REPL_SCRIPT, 'base64').toString('utf8'));
6127
+ const child = spawn('script', ['-qefc', config.command, '/dev/null'], {
6128
+ cwd: config.cwd,
6129
+ stdio: ['pipe', 'pipe', 'pipe'],
6130
+ });
6131
+ let stdout = '';
6132
+ let stderr = '';
6133
+ let cursor = 0;
6134
+ let step = 0;
6135
+ let finished = false;
6136
+
6137
+ function advance() {
6138
+ while (step < config.steps.length) {
6139
+ const current = config.steps[step];
6140
+ const index = stdout.indexOf(current.waitFor, cursor);
6141
+ if (index === -1) return;
6142
+ cursor = index + current.waitFor.length;
6143
+ child.stdin.write(current.send);
6144
+ step++;
6145
+ }
6146
+ }
6147
+
6148
+ child.stdout.on('data', (chunk) => {
6149
+ stdout += chunk;
6150
+ advance();
6151
+ });
6152
+ child.stderr.on('data', (chunk) => {
6153
+ stderr += chunk;
6154
+ });
6155
+
6156
+ const timer = setTimeout(() => {
6157
+ if (finished) return;
6158
+ finished = true;
6159
+ child.kill('SIGKILL');
6160
+ process.stdout.write(JSON.stringify({ status: null, stdout, stderr, timedOut: true, step }));
6161
+ }, config.timeout);
6162
+
6163
+ child.on('close', (status, signal) => {
6164
+ if (finished) return;
6165
+ finished = true;
6166
+ clearTimeout(timer);
6167
+ process.stdout.write(JSON.stringify({ status, signal, stdout, stderr, timedOut: false, step }));
6168
+ });
6169
+ `;
6170
+ const helperResult = spawnSync(process.execPath, ['-e', helper], {
6171
+ cwd: packageRoot,
6172
+ encoding: 'utf8',
6173
+ env: { ...process.env, EYEPROLOG_REPL_SCRIPT: payload },
6174
+ timeout: timeout + 1000,
6175
+ });
6176
+ if (helperResult.error) return helperResult;
6177
+ if (helperResult.status !== 0) return helperResult;
6178
+ let result;
6179
+ try {
6180
+ result = JSON.parse(helperResult.stdout);
6181
+ } catch (error) {
6182
+ return {
6183
+ ...helperResult,
6184
+ error: new Error(`interactive REPL helper returned invalid JSON: ${error.message}`),
6185
+ };
6186
+ }
6187
+ return {
6188
+ status: result.status,
6189
+ stdout: result.stdout,
6190
+ stderr: `${result.stderr ?? ''}${helperResult.stderr ?? ''}`,
6191
+ error: result.timedOut
6192
+ ? Object.assign(new Error(`interactive REPL timed out after step ${result.step}`), { code: 'ETIMEDOUT' })
6193
+ : undefined,
6194
+ };
6195
+ }
6196
+
6089
6197
  function runCli(args, options = {}) {
6090
6198
  return spawnSync(process.execPath, [bin, ...args], {
6091
6199
  cwd: packageRoot,
@@ -7584,9 +7584,7 @@ node test/run-conformance-report.mjs
7584
7584
  ```
7585
7585
 
7586
7586
  `test/conformance/ISO-COMPLIANCE.md` is the processor-requirement ledger for the
7587
- Part 1 conformance audit. It distinguishes implemented/tested families from
7588
- requirements whose normative `shall` clauses, option combinations, or error
7589
- precedence still need one-by-one closure. `test/conformance/ISO-COMPLIANCE.md`
7587
+ Part 1 conformance audit. It records explicit dispositions for the tracked processor, syntax, semantic, built-in, and arithmetic requirements. `test/conformance/ISO-COMPLIANCE.md`
7590
7588
  maps language families to representative executable cases.
7591
7589
  `test/conformance/ISO-IMPLEMENTATION-DEFINED.md` is the ISO 5.4 decision
7592
7590
  index: it enumerates the Part 1 implementation-defined decisions and the
@@ -7595,8 +7593,7 @@ proposals into the licensed baseline. `ISO-TERM-SEMANTICS-MATRIX.md` closes the
7595
7593
  rows, `ISO-PROLOG-TEXT-EXECUTION-MATRIX.md` closes 7.4-7.8 preparation,
7596
7594
  database, conversion, execution, and control, and
7597
7595
  `ISO-EVALUABLE-FUNCTOR-MATRIX.md` closes 7.9/Clause 9 expression and arithmetic
7598
- rows. The exit checklist in `ISO-COMPLIANCE.md` makes the remaining normative and
7599
- unexplained-deviation conditions explicit. `test/conformance/WG17-SYNTAX-STATUS.md` separately traces the vendored active
7596
+ rows. The exit checklist in `ISO-COMPLIANCE.md` records the closure criteria and their evidence. `test/conformance/WG17-SYNTAX-STATUS.md` separately traces the vendored active
7600
7597
  upstream syntax cases. Reviewed cases can pin exact strict-reader outcomes, while
7601
7598
  newly upgraded cases execute directly against the upstream Codex expectation.
7602
7599
 
@@ -7660,29 +7657,18 @@ expansion/`phrase/2-3`, quads, EyeProlog libraries, the `occurs_check` flag,
7660
7657
  automatic tabling, `call_cleanup/2`, and `setup_call_cleanup/3` are outside
7661
7658
  that Part 1 strict surface.
7662
7659
 
7663
- This release establishes the strict-mode mechanism required for the ongoing
7664
- conformance audit; it does **not** yet claim that every processor requirement
7665
- has been independently certified. `test/conformance/ISO-COMPLIANCE.md` tracks
7666
- the remaining normative audit work. Public comparison material used during the audit remains review evidence rather than a duplicated vendored corpus. The executable examples are mostly
7667
- EyeProlog-profile programs using host-supplied goals, character lists, explicit
7668
- integrity relations, automatic tabling, and the EyeProlog library. The strict audit also exercises the complete Part 1 flag
7669
- set and the prescribed 8.14 error precedence for `read_term/3`, `write_term/3`,
7670
- `op/3`, and `current_op/3`; these checks distinguish invalid values from
7671
- valid-but-fixed flag values and reject normal-profile write options at the
7672
- strict boundary. The continuing issue #65 audit also enforces Part 1
7673
- preparation constraints for `dynamic/1`, `multifile/1`, and `discontiguous/1`,
7674
- keeps initialization tied to preparation of a program, tightens stream
7675
- creation/position/EOF behavior and text-vs-binary permission errors, corrects
7676
- Corrigendum 2 `keysort/2` error cases, closes the 5.5.6 Prolog-visible
7677
- side-effect boundary by excluding statistics/cleanup extensions from strict
7678
- mode, closes 5.5.10 by keeping the non-standard evaluable atom `e` outside
7679
- strict mode, closes the row-level 7.1-7.3 term-semantics, 7.4-7.8 preparation/database/control, and 7.9/Clause 9
7680
- arithmetic audits, and pins the permitted arithmetic variation points for
7681
- mixed-type Corrigendum 2 `max/2`/`min/2` plus signed Clause 9.4 bitwise and
7682
- negative-shift behavior. The Clause 9 audit also corrected float-only
7683
- `float_integer_part/1` and `float_fractional_part/1` so integer operands are
7684
- rejected by type before a potentially overflowing integer-to-float conversion.
7685
- The 7.4-7.8 closure also pins cross-text directive state, include/ensure-loaded lifetime, initialization order and one-shot execution, logical-update visibility, empty-versus-unknown procedures, term-to-body conversion, and the general Part 1 control/exception constructs. These are conformance improvements, while the remaining qualifications are:
7660
+ The strict-core audit has explicit dispositions for the Clause 5 processor
7661
+ obligations, Clause 6 syntax and rejection families, Clause 7 term/execution/I/O
7662
+ and error semantics, the 8.2-8.17 built-in families, and Clause 9 evaluable
7663
+ functors. The complete vendored WG17 syntax matrix is a release gate, and each
7664
+ strict-success WG17 observation is also checked through normal mode so syntax
7665
+ extensions cannot reinterpret accepted standard text. Implementation-defined
7666
+ choices—including the Unicode-scalar processor character set, stream details,
7667
+ flag defaults, floating behavior, and signed bitwise/shift semantics—are indexed
7668
+ in `test/conformance/ISO-IMPLEMENTATION-DEFINED.md`. The release-facing closure
7669
+ ledger is `test/conformance/ISO-COMPLIANCE.md`.
7670
+
7671
+ Notable implementation boundaries are:
7686
7672
 
7687
7673
  - zero-arity compound syntax such as `ready()` is represented by the atom
7688
7674
  `ready`;
@@ -7700,11 +7686,9 @@ The 7.4-7.8 closure also pins cross-text directive state, include/ensure-loaded
7700
7686
 
7701
7687
  Write terms explicitly, keep variables uppercase or underscore-prefixed, and
7702
7688
  quote atom names that are neither lowercase plain names nor graphic tokens.
7703
- These boundaries distinguish implemented ISO functionality from certification.
7704
- The EyeProlog corpus verifies this documented profile and strict-core boundary.
7705
- A public full-conformance claim is deferred until the explicit
7706
- exit checklist in `test/conformance/ISO-COMPLIANCE.md` has no unresolved normative
7707
- audits or unexplained deviations.
7689
+ The conformance ledger and release gates verify this documented strict-core
7690
+ boundary. Their closure is implementation evidence, not independent ISO
7691
+ certification.
7708
7692
 
7709
7693
  ### Security and resource use
7710
7694
 
package/why-eyeprolog.md CHANGED
@@ -26,13 +26,14 @@ the published strict baseline. The processor character model is explicitly
26
26
  implementation defined: EyeProlog uses Unicode scalar values as the PCS and as
27
27
  collating-sequence integers in both normal and strict profiles. Strict mode
28
28
  therefore rejects implementation-specific language extensions without changing
29
- that processor choice. Its executable conformance matrix and tests
30
- document the supported behavior, including an executable trace of the vendored
31
- active WG17 syntax cases, cross-profile preservation of all strict-success WG17 syntax outcomes, closed strict side-effect and evaluable-functor extension boundaries, the completed row-level 7.1-7.9 term, preparation/database/control, and arithmetic audits, offline public conversion/variable-metadata audit fixtures, and explicit choices at standardized variation points such as mixed-type
32
- `max/2`/`min/2` and signed bitwise/shift operations. The remaining exit criteria
33
- are recorded explicitly rather than inferred from aggregate test counts. This is
34
- extensive implementation evidence, not a claim that every Part 1, Part 2, or
35
- Part 3 normative requirement has already been certified or closed.
29
+ that processor choice. Its executable conformance matrix records explicit
30
+ dispositions for the Part 1 processor, syntax, semantic, built-in, and arithmetic
31
+ requirements, including the complete vendored WG17 syntax cases and cross-profile
32
+ preservation of strict-success syntax outcomes. Implementation-defined choices
33
+ such as mixed-type `max/2`/`min/2` and signed bitwise/shift operations are pinned
34
+ by regression tests. This is extensive implementation evidence, not an independent
35
+ ISO certification; the Part 2 and Part 3 compatibility profiles also remain
36
+ separate from the Part 1 strict-core claim.
36
37
 
37
38
  ## Why a small implementation?
38
39