eyeling 1.21.1 → 1.21.3
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/HANDBOOK.md +62 -1
- package/README.md +0 -1
- package/package.json +3 -4
- package/test/{builtin-contract.test.js → builtins.test.js} +40 -13
- package/SEMANTICS.md +0 -41
- package/test/fixtures/builtins/bad-export.js +0 -3
- package/test/fixtures/builtins/ok-builtins.js +0 -7
- package/test/fixtures/builtins/ok-default-map.js +0 -7
- package/test/fixtures/builtins/ok-map.js +0 -5
- package/test/fixtures/builtins/ok-register.js +0 -7
package/HANDBOOK.md
CHANGED
|
@@ -31,6 +31,7 @@
|
|
|
31
31
|
- [Appendix D — LLM + Eyeling: A Repeatable Logic Toolchain](#app-d)
|
|
32
32
|
- [Appendix E — How Eyeling reaches 100% on `notation3tests`](#app-e)
|
|
33
33
|
- [Appendix F — The ARC approach: Answer • Reason Why • Check](#app-f)
|
|
34
|
+
- [Appendix G — Eyeling and the W3C CG Notation3 Semantics](#app-g)
|
|
34
35
|
|
|
35
36
|
---
|
|
36
37
|
|
|
@@ -2141,7 +2142,7 @@ In practice, this means:
|
|
|
2141
2142
|
- builtin module loading accepts only the documented export forms
|
|
2142
2143
|
- the helper API exposed by `__buildBuiltinRegistrationApi()` has a fixed key set
|
|
2143
2144
|
- builtin handlers should return an array of substitution objects
|
|
2144
|
-
- accidental helper drift is caught by `test/
|
|
2145
|
+
- accidental helper drift is caught by `test/builtins.test.js`
|
|
2145
2146
|
|
|
2146
2147
|
This is only meant to stop silent breakage. It is **not** a promise that Eyeling can never change the builtin API. If the helper surface ever needs to change, that change should be deliberate, documented, and called out in release notes.
|
|
2147
2148
|
|
|
@@ -3104,3 +3105,63 @@ A file really follows ARC only when the answer, the explanation, and the validat
|
|
|
3104
3105
|
### F.9 Why this style is worth using
|
|
3105
3106
|
|
|
3106
3107
|
This style is worth using because it makes an Eyeling file easier to run, easier to inspect, and easier to trust. The result is visible. The key reason is visible. The check is visible. That makes examples better teaching material, makes policy or computation examples easier to audit, and makes the whole file more reusable as a small reasoning artifact instead of an opaque session transcript.
|
|
3108
|
+
|
|
3109
|
+
<a id="app-g"></a>
|
|
3110
|
+
|
|
3111
|
+
## Appendix G — Eyeling and the W3C CG Notation3 Semantics
|
|
3112
|
+
|
|
3113
|
+
The purpose of this appendix is to say where Eyeling tracks the [W3C CG Notation3 semantics](https://w3c.github.io/N3/spec/semantics) closely, and where Eyeling makes deliberate operational choices of its own.
|
|
3114
|
+
|
|
3115
|
+
The comparison point here is the W3C CG Notation3 semantics document, not a claim that Eyeling is trying to be a line-by-line implementation of that document. Eyeling is a working reasoner, so some choices are shaped by execution, indexing, determinism, and the practical habits of N3 authors.
|
|
3116
|
+
|
|
3117
|
+
### G.1 Where Eyeling is strongly aligned
|
|
3118
|
+
|
|
3119
|
+
- **Core term model (IRIs, literals, variables, blank nodes, lists, quoted formulas):** The semantics document treats N3 terms as IRIs, literals, variables, lists, and graph terms. Eyeling’s internal model matches that shape directly through `Iri`, `Literal`, `Var`, `Blank`, `ListTerm`, and `GraphTerm`.
|
|
3120
|
+
|
|
3121
|
+
- **Quoted formulas need alpha-equivalence / isomorphism:** The semantics document defines isomorphism for graphs and graph terms using consistent renaming. Eyeling implements the same practical idea operationally as alpha-equivalence for `GraphTerm`, with consistent renaming as the criterion for a match.
|
|
3122
|
+
|
|
3123
|
+
- **Rules as implication (and `true` as empty formula):** The semantics document gives a special role to `log:implies` and treats `true` and `false` specially, with `true` corresponding to the empty formula. Eyeling follows that shape: it accepts both `{ P } => { C }` and `{ P } log:implies { C }`, and it treats `true` as `{}`.
|
|
3124
|
+
|
|
3125
|
+
- **Lists as first-class citizens (not just RDF collections):** The semantics document treats lists as genuine N3 terms. Eyeling does the same through `ListTerm`, and also materializes RDF `rdf:first` / `rdf:rest` chains into list terms so one list model can be used throughout the engine.
|
|
3126
|
+
|
|
3127
|
+
### G.2 Where Eyeling diverges or goes beyond the semantics document
|
|
3128
|
+
|
|
3129
|
+
#### G.2.1 Blank nodes in rule bodies: Eyeling chooses common N3 rule-writing practice
|
|
3130
|
+
|
|
3131
|
+
The semantics document describes blank nodes as existentially quantified with local scope. Eyeling intentionally rewrites blank nodes in **rule premises** into variables during normalization. In practice this makes body blanks behave like the placeholders many N3 authors expect when they write rules.
|
|
3132
|
+
|
|
3133
|
+
That is a real semantic choice. It is useful and intentional, but it is not the same as reading blank nodes as existentials everywhere.
|
|
3134
|
+
|
|
3135
|
+
#### G.2.2 Groundness of quoted formulas containing variables
|
|
3136
|
+
|
|
3137
|
+
In the semantics document, whether a graph term is ground depends on whether the underlying graph is closed, and nested formulas can still contain free variables when viewed in isolation. Eyeling makes a pragmatic engine choice: variables inside a `GraphTerm` do not make the surrounding triple non-ground. In the handbook this is summarized as “variables inside formulas do not leak.”
|
|
3138
|
+
|
|
3139
|
+
That supports indexing, matching, and duplicate checks, but it is not a one-to-one restatement of model-theoretic groundness for graph terms.
|
|
3140
|
+
|
|
3141
|
+
#### G.2.3 Eyeling defines operational behavior beyond what the semantics document currently fixes
|
|
3142
|
+
|
|
3143
|
+
The semantics document mainly fixes meaning around implication and the core N3 term/formula model. Eyeling goes further and gives operational meaning to a large standard library of builtins and control features. Examples include `math:*`, `string:*`, `list:*`, `time:*`, `log:includes`, `log:notIncludes`, `log:query`, and scoped closure via `log:conclusion`.
|
|
3144
|
+
|
|
3145
|
+
So Eyeling is not only implementing the semantics document; it is also defining engine behavior for features that the current document does not fully specify.
|
|
3146
|
+
|
|
3147
|
+
#### G.2.4 Inference fuses (`=> false`) are an engine-level procedural feature
|
|
3148
|
+
|
|
3149
|
+
The semantics document discusses `false` in relation to implication and constraints. Eyeling turns `{ ... } => false` into an engine-level hard failure with a visible message and failing exit status. That is a practical tooling feature: it lets a rule act like a checked invariant.
|
|
3150
|
+
|
|
3151
|
+
This is very useful in real programs, but it is an operational behavior of the reasoner, not something a model-theoretic semantics “executes.”
|
|
3152
|
+
|
|
3153
|
+
#### G.2.5 Surface-language coverage is not the same thing as semantic alignment
|
|
3154
|
+
|
|
3155
|
+
The semantics document discusses explicit quantification in its abstract syntax. Eyeling mostly exposes implicit quantification through `?x` variables and blank nodes, together with the rule-normalization choices described earlier. The handbook documents the supported surface forms Eyeling actually parses, which may be narrower than the full abstract surface discussed in the semantics document.
|
|
3156
|
+
|
|
3157
|
+
So even where the underlying ideas line up, the accepted concrete syntax may still be a proper subset.
|
|
3158
|
+
|
|
3159
|
+
### G.3 The practical takeaway
|
|
3160
|
+
|
|
3161
|
+
A good short summary is this:
|
|
3162
|
+
|
|
3163
|
+
- Eyeling is strongly aligned with the N3 semantics on the **core ontology of terms, quoted formulas, implication, and lists**.
|
|
3164
|
+
- Eyeling makes deliberate, implementation-shaped choices around **rule-body blanks, groundness of quoted formulas, and constraint execution**.
|
|
3165
|
+
- Eyeling also defines a wider operational language than the current semantics document, especially through builtins and scoped proof/query features.
|
|
3166
|
+
|
|
3167
|
+
So the handbook and the semantics document are best read as complementary. The semantics document explains the abstract shape of Notation3. The handbook explains how a compact working reasoner realizes that shape, and where it chooses a practical execution model over a purely model-theoretic presentation.
|
package/README.md
CHANGED
|
@@ -16,5 +16,4 @@ echo '@prefix : <http://example.org/> .
|
|
|
16
16
|
|
|
17
17
|
- **Handbook:** [eyereasoner.github.io/eyeling/HANDBOOK](https://eyereasoner.github.io/eyeling/HANDBOOK)
|
|
18
18
|
- **Playground:** [eyereasoner.github.io/eyeling/demo](https://eyereasoner.github.io/eyeling/demo)
|
|
19
|
-
- **Semantics:** [eyereasoner.github.io/eyeling/SEMANTICS](https://eyereasoner.github.io/eyeling/SEMANTICS)
|
|
20
19
|
- **Conformance report:** [codeberg.org/phochste/notation3tests/.../report.md](https://codeberg.org/phochste/notation3tests/src/branch/main/reports/report.md)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eyeling",
|
|
3
|
-
"version": "1.21.
|
|
3
|
+
"version": "1.21.3",
|
|
4
4
|
"description": "A minimal Notation3 (N3) reasoner in JavaScript.",
|
|
5
5
|
"main": "./index.js",
|
|
6
6
|
"keywords": [
|
|
@@ -22,7 +22,6 @@
|
|
|
22
22
|
"LICENSE.md",
|
|
23
23
|
"README.md",
|
|
24
24
|
"HANDBOOK.md",
|
|
25
|
-
"SEMANTICS.md",
|
|
26
25
|
"eyeling-builtins.ttl",
|
|
27
26
|
"eyeling.js",
|
|
28
27
|
"index.js",
|
|
@@ -42,14 +41,14 @@
|
|
|
42
41
|
"build": "node tools/bundle.js",
|
|
43
42
|
"test:packlist": "node test/packlist.test.js",
|
|
44
43
|
"test:api": "node test/api.test.js",
|
|
45
|
-
"test:
|
|
44
|
+
"test:builtins": "node test/builtins.test.js",
|
|
46
45
|
"test:n3gen": "node test/n3gen.test.js",
|
|
47
46
|
"test:examples": "node test/examples.test.js",
|
|
48
47
|
"test:extra": "node test/extra.test.js",
|
|
49
48
|
"test:manifest": "node test/manifest.test.js",
|
|
50
49
|
"test:playground": "node test/playground.test.js",
|
|
51
50
|
"test:package": "node test/package.test.js",
|
|
52
|
-
"test:all": "npm run test:api && npm run test:
|
|
51
|
+
"test:all": "npm run test:api && npm run test:builtins && npm run test:n3gen && npm run test:examples && npm run test:extra && npm run test:manifest && npm run test:playground",
|
|
53
52
|
"pretest": "npm run build && npm run test:packlist",
|
|
54
53
|
"test": "npm run test:all",
|
|
55
54
|
"posttest": "npm run test:package",
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const assert = require('node:assert/strict');
|
|
4
|
-
const path = require('node:path');
|
|
5
4
|
|
|
6
5
|
const TTY = process.stdout.isTTY;
|
|
7
6
|
const C = TTY
|
|
@@ -18,7 +17,6 @@ function fail(msg) {
|
|
|
18
17
|
console.error(`${C.r}FAIL${C.n} ${msg}`);
|
|
19
18
|
}
|
|
20
19
|
|
|
21
|
-
const fixtures = path.join(__dirname, 'fixtures', 'builtins');
|
|
22
20
|
const builtins = require('../lib/builtins');
|
|
23
21
|
require('../lib/engine');
|
|
24
22
|
|
|
@@ -62,8 +60,43 @@ const expectedTermsKeys = [
|
|
|
62
60
|
'Triple',
|
|
63
61
|
'Rule',
|
|
64
62
|
].sort();
|
|
63
|
+
|
|
65
64
|
const expectedNsKeys = ['RDF_NS', 'XSD_NS', 'CRYPTO_NS', 'MATH_NS', 'TIME_NS', 'LIST_NS', 'LOG_NS', 'STRING_NS'].sort();
|
|
66
65
|
|
|
66
|
+
function makeOkMapModule() {
|
|
67
|
+
return {
|
|
68
|
+
'http://example.org/test#ok': ({ subst }) => [subst],
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function makeOkRegisterModule() {
|
|
73
|
+
return {
|
|
74
|
+
register(api) {
|
|
75
|
+
api.registerBuiltin('http://example.org/test#ok-register', ({ subst }) => [subst]);
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function makeOkBuiltinsModule() {
|
|
81
|
+
return {
|
|
82
|
+
builtins: {
|
|
83
|
+
'http://example.org/test#ok-builtins': ({ subst }) => [subst],
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function makeOkDefaultMapModule() {
|
|
89
|
+
return {
|
|
90
|
+
default: {
|
|
91
|
+
'http://example.org/test#ok-default-map': ({ subst }) => [subst],
|
|
92
|
+
},
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function makeBadExportModule() {
|
|
97
|
+
return 42;
|
|
98
|
+
}
|
|
99
|
+
|
|
67
100
|
const cases = [
|
|
68
101
|
{
|
|
69
102
|
name: 'builtin helper API stays stable and frozen',
|
|
@@ -80,23 +113,17 @@ const cases = [
|
|
|
80
113
|
{
|
|
81
114
|
name: 'registerBuiltinModule accepts supported module export forms',
|
|
82
115
|
run() {
|
|
83
|
-
assert.doesNotThrow(() => builtins.registerBuiltinModule(
|
|
84
|
-
assert.doesNotThrow(() =>
|
|
85
|
-
|
|
86
|
-
);
|
|
87
|
-
assert.doesNotThrow(() =>
|
|
88
|
-
builtins.registerBuiltinModule(require(path.join(fixtures, 'ok-builtins.js')), 'ok-builtins'),
|
|
89
|
-
);
|
|
90
|
-
assert.doesNotThrow(() =>
|
|
91
|
-
builtins.registerBuiltinModule(require(path.join(fixtures, 'ok-default-map.js')), 'ok-default-map'),
|
|
92
|
-
);
|
|
116
|
+
assert.doesNotThrow(() => builtins.registerBuiltinModule(makeOkMapModule(), 'ok-map'));
|
|
117
|
+
assert.doesNotThrow(() => builtins.registerBuiltinModule(makeOkRegisterModule(), 'ok-register'));
|
|
118
|
+
assert.doesNotThrow(() => builtins.registerBuiltinModule(makeOkBuiltinsModule(), 'ok-builtins'));
|
|
119
|
+
assert.doesNotThrow(() => builtins.registerBuiltinModule(makeOkDefaultMapModule(), 'ok-default-map'));
|
|
93
120
|
},
|
|
94
121
|
},
|
|
95
122
|
{
|
|
96
123
|
name: 'registerBuiltinModule rejects unsupported module exports',
|
|
97
124
|
run() {
|
|
98
125
|
assert.throws(
|
|
99
|
-
() => builtins.registerBuiltinModule(
|
|
126
|
+
() => builtins.registerBuiltinModule(makeBadExportModule(), 'bad-export'),
|
|
100
127
|
/must export a function, a \{ register\(\) \} object, or an object mapping predicate IRIs to handlers/,
|
|
101
128
|
);
|
|
102
129
|
},
|
package/SEMANTICS.md
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
How does the [Eyeling HANDBOOK](https://eyereasoner.github.io/eyeling/HANDBOOK) line up with the W3C CG [Notation3 Semantics](https://w3c.github.io/N3/spec/semantics) document — and where does it intentionally diverge?
|
|
2
|
-
|
|
3
|
-
## Where Eyeling is strongly aligned
|
|
4
|
-
|
|
5
|
-
- **Core term model (IRIs, literals, variables, blank nodes, lists, quoted formulas):** The semantics spec treats N3 terms as IRIs/literals/variables plus **lists** and **graph terms**. Eyeling’s handbook describes the same internal term universe: `Iri`, `Literal`, `Var`, `Blank`, `ListTerm`, `GraphTerm`.
|
|
6
|
-
|
|
7
|
-
- **Quoted formulas need alpha-equivalence / isomorphism:** The semantics spec defines isomorphism for graphs and graph terms using renaming mappings (including special handling for nested scopes). Eyeling implements this operationally as **alpha-equivalence for `GraphTerm`**, explicitly describing “consistent renaming” as the match criterion.
|
|
8
|
-
|
|
9
|
-
- **Rules as implication (and `true` as empty formula):** The semantics spec defines log-semantics for `log:implies` and explicitly treats boolean `true`/`false` as special literals, with `true` corresponding to the empty formula. Eyeling’s parser/normalizer explicitly supports `{P} => {C}` and `{P} log:implies {C}`, and treats `true` as `{}`.
|
|
10
|
-
|
|
11
|
-
- **Lists as first-class citizens (not just RDF collections):** The semantics spec treats lists as proper N3 terms. Eyeling uses concrete `ListTerm`s and even materializes RDF `rdf:first`/`rdf:rest` chains into list terms to operate uniformly.
|
|
12
|
-
|
|
13
|
-
## Where Eyeling diverges or goes beyond the semantics doc
|
|
14
|
-
|
|
15
|
-
### 1) Blank nodes in **rule bodies**: Eyeling chooses “N3 practice” over “bnodes are existential”
|
|
16
|
-
|
|
17
|
-
The semantics doc states (for concrete syntax intuition) that **blank nodes correspond to existentially quantified variables** with **local scope**. Eyeling _intentionally_ rewrites blanks in **premises** into variables (“universally-quantified placeholders”), to avoid “existential in the body” behavior.
|
|
18
|
-
|
|
19
|
-
This is a _real semantic choice_: it matches how many people _write_ N3 rules, but it is not the same as a straightforward “bnodes are existentials everywhere” reading.
|
|
20
|
-
|
|
21
|
-
### 2) “Groundness” of quoted formulas containing variables
|
|
22
|
-
|
|
23
|
-
In the semantics spec, whether a graph term is ground depends on whether the underlying graph is closed (no free variables), and it discusses how variables can appear free when you isolate a nested graph term. Eyeling explicitly makes a pragmatic choice: **variables inside a `GraphTerm` do not make the surrounding triple non-ground** (“variables inside formulas don’t leak”).
|
|
24
|
-
|
|
25
|
-
That’s convenient for operational indexing/matching, but it doesn’t mirror the model-theoretic notion of ground graph terms one-to-one.
|
|
26
|
-
|
|
27
|
-
### 3) Eyeling implements lots of behavior the semantics doc does not yet define
|
|
28
|
-
|
|
29
|
-
The semantics report currently only gives special meaning to `log:implies` (and says LP is planned to be extended). Eyeling defines a large operational “standard library” of builtins and advanced control features (e.g., scoped querying / snapshotting). For example, it gives `log:includes`/`log:notIncludes` a two-phase snapshot semantics for determinism.
|
|
30
|
-
|
|
31
|
-
So: Eyeling is **ahead of / outside** what `semantics.html` formally specifies today.
|
|
32
|
-
|
|
33
|
-
### 4) Constraint handling via “inference fuses” (`=> false`) is operational
|
|
34
|
-
|
|
35
|
-
The semantics doc includes a notion of `false` in connection with `log:implies` constraints. Eyeling turns `{...} => false` into an _engine-level hard failure_ (exit status, message), i.e., a procedural constraint mechanism rather than just a semantic condition.
|
|
36
|
-
|
|
37
|
-
That’s useful in tooling, but it’s not something the model-theoretic semantics itself “does” (it defines truth/entailment, not process control).
|
|
38
|
-
|
|
39
|
-
### 5) Possible coverage gaps vs full N3 surface language (not strictly “semantics.html”, but relevant)
|
|
40
|
-
|
|
41
|
-
Eyeling’s handbook lists supported directives/tokens (`@prefix`, `@base`, etc.) but does not mention explicit quantifier directives like `@forAll` / `@forSome`. The semantics document leans on explicit quantification in its **abstract syntax** discussion. So Eyeling appears to support _implicit_ quantification via `?x` and blanks (plus its own rule-normalization choices), but may not implement the full explicit-quantifier surface syntax.
|